Skip to content
This repository was archived by the owner on Oct 11, 2024. It is now read-only.
Closed
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
11 changes: 5 additions & 6 deletions .keytransparency.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
log-key: "../trillian/testdata/log-rpc-server.pubkey.pem"
kt-url: "localhost:8080"
kt-cert: "genfiles/server.crt"
vrf: "genfiles/vrf-pubkey.pem"
kt-key: "genfiles/server.crt"
kt-sig: "genfiles/p256-pubkey.pem"
domain: "example.com"
map-id: 0
kt-url: "35.184.134.53:8080"
log-key: "genfiles/trillian-log.pem"
map-key: "genfiles/trillian-map.pem"
client-secret: "client_secret.json"
service-key: ""
service-key: ""
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ development.
### Setup
1. Install [Go 1.7](https://golang.org/doc/install).
2. `go get -u github.com/google/keytransparency/cmd/keytransparency-client `
3. Get an [OAuth client ID](https://console.developers.google.com/apis/credentials) and download the generated JSON file.
4. Run the client setup tool: `./scripts/prepare_client.sh`
3. Get an [OAuth client ID](https://console.developers.google.com/apis/credentials) and download the generated JSON file to `client_secret.json`.
4. Run the client setup tool: `./scripts/prepare_client.sh`

### Client operations

#### Publish a public key

```sh
keytransparency-client authorized-keys --help`
keytransparency-client authorized-keys --help
keytransparency-client authorized-keys add --generate --type=ecdsa --activate
keytransparency-client post user@domain.com app1 --config=./.keytransparency.yaml -d 'dGVzdA==' #Base64
```
Expand Down
66 changes: 31 additions & 35 deletions cmd/keytransparency-client/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,32 @@ import (
"log"
"net"
"os"
"strings"
"time"

"github.com/google/keytransparency/cmd/keytransparency-client/grpcc"
"github.com/google/keytransparency/core/authentication"
"github.com/google/keytransparency/core/client/kt"
"github.com/google/keytransparency/core/crypto/keymaster"
"github.com/google/keytransparency/core/crypto/signatures"
"github.com/google/keytransparency/core/crypto/vrf"
"github.com/google/keytransparency/core/crypto/vrf/p256"
gauth "github.com/google/keytransparency/impl/google/authentication"
pb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service"

"github.com/google/trillian"
"github.com/google/trillian/client"
"github.com/google/trillian/crypto/keys"
"github.com/google/trillian/merkle/hashers"
_ "github.com/google/trillian/merkle/objhasher" // Register objhasher
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/oauth"

_ "github.com/google/trillian/merkle/coniks" // Register coniks
_ "github.com/google/trillian/merkle/maphasher" // Register maphasher
_ "github.com/google/trillian/merkle/objhasher" // Register objhasher

gauth "github.com/google/keytransparency/impl/google/authentication"
pb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service"
)

var (
Expand Down Expand Up @@ -83,11 +85,11 @@ func init() {
RootCmd.PersistentFlags().String("log-url", "", "URL of Certificate Transparency server")
RootCmd.PersistentFlags().String("log-key", "", "Path to public key PEM for Trillian Log server")

RootCmd.PersistentFlags().Int64("map-id", 0, "Map ID of the backend map server")
RootCmd.PersistentFlags().String("map-key", "genfiles/trillian-map.pem", "Path to public key for signed map heads")
RootCmd.PersistentFlags().String("map-hasher", "TEST_MAP_HASHER", "Hash strategy used by map")

RootCmd.PersistentFlags().String("kt-url", "", "URL of Key Transparency server")
RootCmd.PersistentFlags().String("kt-key", "testdata/server.crt", "Path to public key for Key Transparency")
RootCmd.PersistentFlags().String("kt-sig", "testdata/p256-pubkey.pem", "Path to public key for signed map heads")
RootCmd.PersistentFlags().String("kt-cert", "genfiles/server.crt", "Path to public key for Key Transparency")

RootCmd.PersistentFlags().String("fake-auth-userid", "", "userid to present to the server as identity for authentication. Only succeeds if fake auth is enabled on the server side.")

Expand All @@ -101,8 +103,8 @@ func init() {

// initConfig reads in config file and ENV variables if set.
func initConfig() {
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv() // Read in environment variables that match.

if cfgFile != "" {
viper.SetConfigFile(cfgFile)
if err := viper.ReadInConfig(); err != nil {
Expand Down Expand Up @@ -174,30 +176,19 @@ func getServiceCreds(serviceKeyFile string) (credentials.PerRPCCredentials, erro
return oauth.NewServiceAccountFromKey(b, gauth.RequiredScopes...)
}

func readSignatureVerifier(ktPEM string) (signatures.Verifier, error) {
pem, err := ioutil.ReadFile(ktPEM)
if err != nil {
return nil, err
}
ver, err := keymaster.NewVerifierFromPEM(pem)
if err != nil {
return nil, err
}
return ver, nil
}

func getClient(cc *grpc.ClientConn, mapID int64, vrfPubFile, ktSig string, log client.LogVerifier) (*grpcc.Client, error) {
func getClient(cc *grpc.ClientConn, vrfPubFile, mapKeyFile string, mapHasher hashers.MapHasher, log client.LogVerifier) (*grpcc.Client, error) {
// Create Key Transparency client.
vrfKey, err := readVrfKey(vrfPubFile)
if err != nil {
return nil, err
}
verifier, err := readSignatureVerifier(ktSig)
mapKey, err := keys.NewFromPublicPEMFile(mapKeyFile)
if err != nil {
return nil, fmt.Errorf("error reading key transparency PEM: %v", err)
}

cli := pb.NewKeyTransparencyServiceClient(cc)
return grpcc.New(mapID, cli, vrfKey, verifier, log), nil
return grpcc.New(cli, vrfKey, mapKey, mapHasher, log), nil
}

func dial(ktURL, caFile, clientSecretFile string, serviceKeyFile string) (*grpc.ClientConn, error) {
Expand Down Expand Up @@ -255,31 +246,36 @@ func dial(ktURL, caFile, clientSecretFile string, serviceKeyFile string) (*grpc.
func GetClient(clientSecretFile string) (*grpcc.Client, error) {
vrfFile := viper.GetString("vrf")
ktURL := viper.GetString("kt-url")
ktPEM := viper.GetString("kt-key")
ktSig := viper.GetString("kt-sig")
mapID := viper.GetInt64("map-id")
ktCert := viper.GetString("kt-cert")
mapKey := viper.GetString("map-key")
mapHashStrategy := viper.GetString("map-hasher")
logPEM := viper.GetString("log-key")
serviceKeyFile := viper.GetString("service-key")
cc, err := dial(ktURL, ktPEM, clientSecretFile, serviceKeyFile)
cc, err := dial(ktURL, ktCert, clientSecretFile, serviceKeyFile)
if err != nil {
return nil, fmt.Errorf("Error Dialing %v: %v", ktURL, err)
return nil, fmt.Errorf("Dial(%v): %v", ktURL, err)
}

// Log verifier.
logPubKey, err := keys.NewFromPublicPEMFile(logPEM)
if err != nil {
return nil, fmt.Errorf("Failed to open public key %v: %v", logPubKey, err)
return nil, fmt.Errorf("NewFromPublicPEMFile(%v): %v", logPubKey, err)
}

hasher, err := hashers.NewLogHasher(trillian.HashStrategy_OBJECT_RFC6962_SHA256)
logHasher, err := hashers.NewLogHasher(trillian.HashStrategy_OBJECT_RFC6962_SHA256)
if err != nil {
return nil, fmt.Errorf("Failed retrieving LogHasher from registry: %v", err)
}
log := client.NewLogVerifier(hasher, logPubKey)
log := client.NewLogVerifier(logHasher, logPubKey)

mapHasher, err := hashers.NewMapHasher(trillian.HashStrategy(trillian.HashStrategy_value[mapHashStrategy]))
if err != nil {
return nil, fmt.Errorf("Failed retrieving MapHasher from registry: %v", err)
}

c, err := getClient(cc, mapID, vrfFile, ktSig, log)
c, err := getClient(cc, vrfFile, mapKey, mapHasher, log)
if err != nil {
return nil, fmt.Errorf("Error creating client: %v", err)
return nil, fmt.Errorf("error creating client: %v", err)
}
return c, nil
}
14 changes: 7 additions & 7 deletions cmd/keytransparency-client/grpcc/grpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,10 @@ import (
"github.com/google/keytransparency/core/crypto/vrf"
"github.com/google/keytransparency/core/mutator"
"github.com/google/keytransparency/core/mutator/entry"
"github.com/google/keytransparency/core/tree/sparse"
tv "github.com/google/keytransparency/core/tree/sparse/verifier"

"github.com/golang/protobuf/proto"
"github.com/google/trillian/client"
"github.com/google/trillian/merkle/hashers"
"golang.org/x/net/context"
"google.golang.org/grpc"

Expand Down Expand Up @@ -91,15 +90,15 @@ type Client struct {
}

// New creates a new client.
func New(mapID int64,
client spb.KeyTransparencyServiceClient,
func New(client spb.KeyTransparencyServiceClient,
vrf vrf.PublicKey,
verifier crypto.PublicKey,
mapKey crypto.PublicKey,
mapHasher hashers.MapHasher,
log client.LogVerifier) *Client {
return &Client{
cli: client,
vrf: vrf,
kt: kt.New(vrf, tv.New(mapID, sparse.CONIKSHasher), verifier, log),
kt: kt.New(vrf, mapHasher, mapKey, log),
log: log,
mutator: entry.New(),
RetryCount: 1,
Expand Down Expand Up @@ -241,7 +240,8 @@ func (c *Client) Retry(ctx context.Context, req *tpb.UpdateEntryRequest) error {
}

// Check if the response is a replay.
if got, want := updateResp.GetProof().GetLeafProof().Leaf.LeafValue, req.GetEntryUpdate().GetUpdate().GetKeyValue().GetValue(); !bytes.Equal(got, want) {
if got, want := updateResp.GetProof().GetLeafProof().GetLeaf().GetLeafValue(),
req.GetEntryUpdate().GetUpdate().GetKeyValue().GetValue(); !bytes.Equal(got, want) {
return ErrRetry
}
return nil
Expand Down
55 changes: 30 additions & 25 deletions core/client/kt/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package kt

import (
"bytes"
"crypto"
"encoding/json"
"errors"
Expand All @@ -24,12 +25,12 @@ import (

"github.com/google/keytransparency/core/crypto/commitments"
"github.com/google/keytransparency/core/crypto/vrf"
"github.com/google/keytransparency/core/tree/sparse"
tv "github.com/google/keytransparency/core/tree/sparse/verifier"

"github.com/golang/protobuf/proto"
"github.com/google/trillian/client"
tcrypto "github.com/google/trillian/crypto"
"github.com/google/trillian/merkle"
"github.com/google/trillian/merkle/hashers"
"golang.org/x/net/context"

tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types"
Expand All @@ -46,22 +47,22 @@ var (

// Verifier is a client helper library for verifying request and responses.
type Verifier struct {
vrf vrf.PublicKey
tree *tv.Verifier
sig crypto.PublicKey
log client.LogVerifier
vrf vrf.PublicKey
hasher hashers.MapHasher
mapKey crypto.PublicKey
log client.LogVerifier
}

// New creates a new instance of the client verifier.
func New(vrf vrf.PublicKey,
tree *tv.Verifier,
sig crypto.PublicKey,
hasher hashers.MapHasher,
mapKey crypto.PublicKey,
log client.LogVerifier) *Verifier {
return &Verifier{
vrf: vrf,
tree: tree,
sig: sig,
log: log,
vrf: vrf,
hasher: hasher,
mapKey: mapKey,
log: log,
}
}

Expand Down Expand Up @@ -96,36 +97,40 @@ func (v *Verifier) VerifyGetEntryResponse(ctx context.Context, userID, appID str

index, err := v.vrf.ProofToHash(vrf.UniqueID(userID, appID), in.VrfProof)
if err != nil {
Vlog.Printf("✗ VRF verification failed.")
Vlog.Printf("✗ Index verification failed.")
return fmt.Errorf("vrf.ProofToHash(%v, %v): %v", userID, appID, err)
}
Vlog.Printf("✓ VRF verified.")

leafProof := in.GetLeafProof()
if leafProof == nil {
return ErrNilProof
if got, want := in.GetLeafProof().GetLeaf().GetIndex(), index[:]; !bytes.Equal(got, want) {
return fmt.Errorf("Leaf.Index: %x, want %x", got, want)
}

if err := v.tree.VerifyProof(leafProof.Inclusion, index[:], leafProof.Leaf.LeafValue, sparse.FromBytes(in.GetSmr().RootHash)); err != nil {
Vlog.Printf("✗ Sparse tree proof verification failed.")
return fmt.Errorf("tree.VerifyProof(): %v", err)
Vlog.Printf("✓ Index verified.")

mapID := in.GetSmr().GetMapId()
leafValue := in.GetLeafProof().GetLeaf().GetLeafValue()
leafHash := v.hasher.HashLeaf(mapID, index[:], v.hasher.BitLen(), leafValue)
proof := in.GetLeafProof().GetInclusion()
expectedRoot := in.GetSmr().GetRootHash()
if err := merkle.VerifyMapInclusionProof(mapID, index[:], leafHash, expectedRoot, proof, v.hasher); err != nil {
Vlog.Printf("✗ Map inclusion proof failed.")
return fmt.Errorf("VerifyMapInclusionProof(): %v", err)
}
Vlog.Printf("✓ Sparse tree proof verified.")
Vlog.Printf("✓ Map inclusion proof verified.")

// SignedMapRoot contains its own signature. To verify, we need to create a local
// copy of the object and return the object to the state it was in when signed
// by removing the signature from the object.
smr := *in.GetSmr()
smr.Signature = nil // Remove the signature from the object to be verified.
if err := tcrypto.VerifyObject(v.sig, smr, in.GetSmr().Signature); err != nil {
Vlog.Printf("? smr: %#v", smr)
if err := tcrypto.VerifyObject(v.mapKey, smr, in.GetSmr().GetSignature()); err != nil {
Vlog.Printf("✗ Signed Map Head signature verification failed.")
return fmt.Errorf("sig.Verify(SMR): %v", err)
}
Vlog.Printf("✓ Signed Map Head signature verified.")

// Verify consistency proof between root and newroot.
// TODO(gdbelvin): Gossip root.
if err := v.log.VerifyRoot(trusted, in.LogRoot, in.LogConsistency); err != nil {
if err := v.log.VerifyRoot(trusted, in.GetLogRoot(), in.GetLogConsistency()); err != nil {
return fmt.Errorf("VerifyRoot(%v, %v): %v", in.LogRoot, in.LogConsistency, err)
}
Vlog.Printf("✓ Log root updated.")
Expand Down
5 changes: 4 additions & 1 deletion core/client/kt/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"testing"

"github.com/google/keytransparency/core/crypto/commitments"
"github.com/google/trillian/merkle/coniks"

"github.com/golang/protobuf/proto"

Expand Down Expand Up @@ -46,7 +47,7 @@ func TestVerifyCommitment(t *testing.T) {
fakeEntryData := validEntryData[:len(validEntryData)-1]

// Create a dummy client verifier.
verifier := New(nil, nil, nil, nil)
verifier := New(0, nil, coniks.Default, nil, nil)
for _, tc := range []struct {
userID, appID string
entryData []byte
Expand All @@ -71,3 +72,5 @@ func TestVerifyCommitment(t *testing.T) {
}
}
}

// TODO(gbelvin): add test for VerifyGetEntryResponse.
16 changes: 5 additions & 11 deletions core/keyserver/keyserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,11 @@ func (s *Server) getEntry(ctx context.Context, userID, appID string, firstTreeSi
glog.Errorf("GetLeaves(): %v", err)
return nil, grpc.Errorf(codes.Internal, "Failed fetching map leaf")
}
if got, want := len(getResp.MapLeafInclusion), 1; got != want {
if got, want := len(getResp.GetMapLeafInclusion()), 1; got != want {
glog.Errorf("GetLeaves() len: %v, want %v", got, want)
return nil, grpc.Errorf(codes.Internal, "Failed fetching map leaf")
}
neighbors := getResp.MapLeafInclusion[0].Inclusion
leaf := getResp.MapLeafInclusion[0].Leaf.LeafValue
leaf := getResp.MapLeafInclusion[0].GetLeaf().GetLeafValue()

var committed *tpb.Committed
if leaf != nil {
Expand Down Expand Up @@ -177,14 +176,9 @@ func (s *Server) getEntry(ctx context.Context, userID, appID string, firstTreeSi
}

return &tpb.GetEntryResponse{
VrfProof: proof,
Committed: committed,
LeafProof: &trillian.MapLeafInclusion{
Inclusion: neighbors,
Leaf: &trillian.MapLeaf{
LeafValue: leaf,
},
},
VrfProof: proof,
Committed: committed,
LeafProof: getResp.MapLeafInclusion[0],
Smr: getResp.GetMapRoot(),
LogRoot: logRoot.GetSignedLogRoot(),
LogConsistency: logConsistency.GetProof().GetHashes(),
Expand Down
Loading