From c52a7f01a8f91a43181f8fbc0609ae8144ee8a9e Mon Sep 17 00:00:00 2001 From: Antonio Marcedone Date: Tue, 8 Aug 2017 18:50:59 -0700 Subject: [PATCH 01/12] Create the gobindClient package, which allows a client to be instantiated through gobind. Add support for fetching entries from go directly (i.e. client.GetEntry) and to verify a proto GetEntryResponse obtained separately. --- core/client/gobindClient/client.go | 192 +++++++++++++++++++++++++++++ core/client/kt/verify.go | 81 +++++++++++- 2 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 core/client/gobindClient/client.go diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go new file mode 100644 index 000000000..16e6888f8 --- /dev/null +++ b/core/client/gobindClient/client.go @@ -0,0 +1,192 @@ +// TODO(amarcedone) : rename package to gobind_client after https://github.com/golang/go/issues/17359 is solved. +package gobindClient + +import ( + "context" + "fmt" + "github.com/google/keytransparency/cmd/keytransparency-client/grpcc" + "github.com/google/trillian" + "github.com/google/trillian/client" + "github.com/google/trillian/crypto/keys/pem" + "github.com/google/trillian/merkle/hashers" + _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered (needed by the bGetVerifierFromParams function) + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "net" + "time" + + tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" + + "crypto/tls" + "crypto/x509" + "github.com/gogo/protobuf/proto" + "github.com/google/keytransparency/core/client/kt" + "github.com/google/keytransparency/core/crypto/keymaster" + "github.com/google/keytransparency/core/crypto/vrf/p256" + pb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service" + "log" +) + +type BClientParams struct { + KtURL string + MapID int64 + KtTLSCertPEM []byte + VrfPubPEM []byte + KtSigPubKey []byte + LogPEM []byte +} + +// TODO(amarcedone) consider persisting the client or at least the trusted smr, to gain efficiency and stronger consistency guarantees. + +func NewBClientParams(KtURL string, MapID int64, KtTLSCertPEM, VrfPubPEM, KtSigPubKey, LogPEM []byte) *BClientParams { + // Note: byte arrays need to be explicitly cloned due to some gobind limitations. + cKtTLSCertPEM := make([]byte, len(KtTLSCertPEM)) + copy(cKtTLSCertPEM, KtTLSCertPEM) + cVrfPubPEM := make([]byte, len(VrfPubPEM)) + copy(cVrfPubPEM, VrfPubPEM) + cKtSigPubKey := make([]byte, len(KtSigPubKey)) + copy(cKtSigPubKey, KtSigPubKey) + cLogPEM := make([]byte, len(LogPEM)) + copy(cLogPEM, LogPEM) + + return &BClientParams{KtURL, MapID, cKtTLSCertPEM, cVrfPubPEM, cKtSigPubKey, cLogPEM} +} + +func BGetEntry(timeoutInMilliseconds int, clientParams *BClientParams, userID, appID string) ([]byte, error) { + + timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond + c, err := GetClient(*clientParams, "") + if err != nil { + return nil, fmt.Errorf("GetEntry failed: error connecting: %v", err) + } + ctx, _ := context.WithTimeout(context.Background(), timeout) + entry, smr, err := c.GetEntry(ctx, userID, appID) + if err != nil { + return nil, fmt.Errorf("GetEntry failed: %v", err) + } + // TODO(amarcedone): Consider returning or persisting smr it to verify consistency over time + _ = smr + //encodedSmr, err := proto.Marshal(smr) + //if err != nil { + // return nil, fmt.Errorf("GetEntry failed: error serializing smr: %v", err) + //} + + return entry, nil +} + +func GetClient(clientParams BClientParams, clientSecretFile string) (*grpcc.Client, error) { + // TODO(amarcedone) For now clientSecretFile is not needed as there is no authentication. Consider removing. + + cc, err := dial(clientParams.KtURL, clientParams.KtTLSCertPEM, clientSecretFile) + if err != nil { + return nil, fmt.Errorf("Error Dialing %v: %v", clientParams.KtURL, err) + } + + // Log verifier. + logPubKey, err := pem.UnmarshalPublicKey(string(clientParams.LogPEM)) + if err != nil { + return nil, fmt.Errorf("Failed to open public key %v: %v", string(clientParams.LogPEM), err) + } + + hasher, 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) + + verifier, err := keymaster.NewVerifierFromPEM(clientParams.KtSigPubKey) + if err != nil { + return nil, fmt.Errorf("Error creating verifier from PEM encoded key: %v", err) + } + + vrfVerifier, err := p256.NewVRFVerifierFromPEM(clientParams.VrfPubPEM) + if err != nil { + return nil, fmt.Errorf("Error parsing vrf public key: %v", err) + } + + cli := pb.NewKeyTransparencyServiceClient(cc) + return grpcc.New(cli, vrfVerifier, verifier, log), nil +} + +func dial(ktURL string, caPEM []byte, clientSecretFile string) (*grpc.ClientConn, error) { + // TODO(amarcedone) For now clientSecretFile is not needed as there is no authentication. Consider removing. + + var opts []grpc.DialOption + // TODO(amarcedone) Copied from root.go. Figure out why we have "if true" here. Perhaps for scope? + if true { + host, _, err := net.SplitHostPort(ktURL) + if err != nil { + return nil, err + } + var creds credentials.TransportCredentials + if len(caPEM) != 0 { + var err error + cp := x509.NewCertPool() + if !cp.AppendCertsFromPEM(caPEM) { + return nil, fmt.Errorf("credentials: failed to append certificates") + } + creds, err = credentials.NewTLS(&tls.Config{ServerName: host, RootCAs: cp}), nil + if err != nil { + return nil, err + } + } else { + // Use the local set of root certs. + creds = credentials.NewClientTLSFromCert(nil, host) + } + opts = append(opts, grpc.WithTransportCredentials(creds)) + } + + // AUTHENTICATION is not needed for gobind clients as they only perform get requests. + //// Add authentication information for the grpc. Only one type of credential + //// should exist in an RPC call. Fake credentials have the highest priority, followed + //// by Client credentials and Service Credentials. + //fakeUserID := viper.GetString("fake-auth-userid") + //switch { + //case fakeUserID != "": + // opts = append(opts, grpc.WithPerRPCCredentials( + // authentication.GetFakeCredential(fakeUserID))) + //case clientSecretFile != "": + // creds, err := getCreds(clientSecretFile) + // if err != nil { + // return nil, err + // } + // opts = append(opts, grpc.WithPerRPCCredentials(creds)) + //case serviceKeyFile != "": + // creds, err := getServiceCreds(serviceKeyFile) + // if err != nil { + // return nil, err + // } + // opts = append(opts, grpc.WithPerRPCCredentials(creds)) + //} + + cc, err := grpc.Dial(ktURL, opts...) + if err != nil { + return nil, err + } + return cc, nil +} + +func BSetCustomLogger(writer BWriter) { + kt.Vlog = log.New(writer, "", log.Lshortfile) +} + +// Local copy of io.Writer interface used to redirect logs. +type BWriter interface { + Write(p []byte) (n int, err error) +} + +// TODO(amarcedone): remove the following two functions. +func BGetTestTrillianSignedLogRoot() ([]byte, error) { + p, err := proto.Marshal(&trillian.SignedLogRoot{}) + if err != nil { + return []byte{}, err + } + return p, nil +} +func BGetTestTpbGetEntryResponse() ([]byte, error) { + p, err := proto.Marshal(&tpb.GetEntryResponse{}) + if err != nil { + return []byte{}, err + } + return p, nil +} diff --git a/core/client/kt/verify.go b/core/client/kt/verify.go index d11d0e290..768424789 100644 --- a/core/client/kt/verify.go +++ b/core/client/kt/verify.go @@ -23,17 +23,21 @@ import ( "log" "github.com/google/keytransparency/core/crypto/commitments" + "github.com/google/keytransparency/core/crypto/keymaster" "github.com/google/keytransparency/core/crypto/vrf" + "github.com/google/keytransparency/core/crypto/vrf/p256" + tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" "github.com/golang/protobuf/proto" "github.com/google/trillian" "github.com/google/trillian/client" tcrypto "github.com/google/trillian/crypto" + "github.com/google/trillian/crypto/keys/pem" "github.com/google/trillian/merkle" "github.com/google/trillian/merkle/hashers" + "github.com/google/trillian/merkle/maphasher" + _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered (needed by the bGetVerifierFromParams function) "golang.org/x/net/context" - - tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" ) var ( @@ -148,3 +152,76 @@ func (v *Verifier) VerifyGetEntryResponse(ctx context.Context, userID, appID str Vlog.Printf("✓ Log inclusion proof verified.") return nil } + +type BVerifierParams struct { + MapID int64 + VrfPubPEM []byte + KtPEM []byte + LogPEM []byte +} + +func NewBVerifierParams(MapID int64, VrfPubPEM, KtPEM, LogPEM []byte) *BVerifierParams { + // Note: byte arrays need to be explicitly cloned due to some gobind limitations. + cVrfPubPEM := make([]byte, len(VrfPubPEM)) + copy(cVrfPubPEM, VrfPubPEM) + cKtPEM := make([]byte, len(KtPEM)) + copy(cKtPEM, KtPEM) + cLogPEM := make([]byte, len(LogPEM)) + copy(cLogPEM, LogPEM) + + return &BVerifierParams{MapID, cVrfPubPEM, cKtPEM, cLogPEM} +} + +func bGetVerifierFromParams(p BVerifierParams) (*Verifier, error) { + + vrf, err := p256.NewVRFVerifierFromPEM(p.VrfPubPEM) + if err != nil { + return nil, fmt.Errorf("Error parsing vrf public key: %v", err) + } + + // TODO this maphasher implementation is ok for debug only. Update. + maphasher := maphasher.Default + + // Verifier + ver, err := keymaster.NewVerifierFromPEM(p.KtPEM) + if err != nil { + return nil, fmt.Errorf("Error creating verifier from PEM encoded key: %v", err) + } + + // log can verify Trillian Logs. + logPubKey, err := pem.UnmarshalPublicKey(string(p.LogPEM)) + if err != nil { + return nil, fmt.Errorf("Failed to open public key %v: %v", logPubKey, err) + } + hasher, 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) + + return New(vrf, maphasher, ver, log), nil +} + +func BVerifyGetEntryResponse(verParam *BVerifierParams, userID string, appID string, + trusted_trillianSignedLogRoot []byte, in_tpbGetEntryResponse []byte) error { + + v, err := bGetVerifierFromParams(*verParam) + if err != nil { + return fmt.Errorf("Couldn't build verifier: %v", err) + } + + trusted := &trillian.SignedLogRoot{} + err = proto.Unmarshal(trusted_trillianSignedLogRoot, trusted) + if err != nil { + return err + } + + in := &tpb.GetEntryResponse{} + err = proto.Unmarshal(in_tpbGetEntryResponse, in) + if err != nil { + return err + } + + // TODO(amarcedone) Is context.Background() appropriate here? + return v.VerifyGetEntryResponse(context.Background(), userID, appID, trusted, in) +} From 45079cd7fe0e9223f7ff1e6fedc7207df3076c3b Mon Sep 17 00:00:00 2001 From: Antonio Marcedone Date: Tue, 8 Aug 2017 18:57:48 -0700 Subject: [PATCH 02/12] Remove dead code. --- core/client/gobindClient/client.go | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 16e6888f8..885c820ae 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -173,20 +173,4 @@ func BSetCustomLogger(writer BWriter) { // Local copy of io.Writer interface used to redirect logs. type BWriter interface { Write(p []byte) (n int, err error) -} - -// TODO(amarcedone): remove the following two functions. -func BGetTestTrillianSignedLogRoot() ([]byte, error) { - p, err := proto.Marshal(&trillian.SignedLogRoot{}) - if err != nil { - return []byte{}, err - } - return p, nil -} -func BGetTestTpbGetEntryResponse() ([]byte, error) { - p, err := proto.Marshal(&tpb.GetEntryResponse{}) - if err != nil { - return []byte{}, err - } - return p, nil -} +} \ No newline at end of file From 4314dad9c3ef4bec79bc283d7e0a3173603fcb74 Mon Sep 17 00:00:00 2001 From: Antonio Marcedone Date: Tue, 8 Aug 2017 19:58:06 -0700 Subject: [PATCH 03/12] Remove unused imports --- core/client/gobindClient/client.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 885c820ae..eda2450e5 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -15,11 +15,9 @@ import ( "net" "time" - tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" "crypto/tls" "crypto/x509" - "github.com/gogo/protobuf/proto" "github.com/google/keytransparency/core/client/kt" "github.com/google/keytransparency/core/crypto/keymaster" "github.com/google/keytransparency/core/crypto/vrf/p256" From 7006ebffe4ecf9ad819011da6b8868d6248b8fef Mon Sep 17 00:00:00 2001 From: Antonio Marcedone Date: Thu, 17 Aug 2017 10:41:51 -0700 Subject: [PATCH 04/12] gobindClient can now autoconfig from the server DomainInfo service. --- core/client/gobindClient/client.go | 46 ++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index eda2450e5..239f7a7ef 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -21,8 +21,11 @@ import ( "github.com/google/keytransparency/core/client/kt" "github.com/google/keytransparency/core/crypto/keymaster" "github.com/google/keytransparency/core/crypto/vrf/p256" - pb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service" + spb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service" + tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" + "log" + "github.com/google/trillian/merkle/coniks" ) type BClientParams struct { @@ -52,12 +55,19 @@ func NewBClientParams(KtURL string, MapID int64, KtTLSCertPEM, VrfPubPEM, KtSigP func BGetEntry(timeoutInMilliseconds int, clientParams *BClientParams, userID, appID string) ([]byte, error) { - timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond - c, err := GetClient(*clientParams, "") + //timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond + //c, err := GetClient(*clientParams, "") + + timeout := time.Duration(700) * time.Millisecond + ctx, _ := context.WithTimeout(context.Background(), timeout) + + //c, err := GetClient(*clientParams, "") + c, err := GetClientWithAutoConfig(ctx, *clientParams) + + if err != nil { return nil, fmt.Errorf("GetEntry failed: error connecting: %v", err) } - ctx, _ := context.WithTimeout(context.Background(), timeout) entry, smr, err := c.GetEntry(ctx, userID, appID) if err != nil { return nil, fmt.Errorf("GetEntry failed: %v", err) @@ -72,6 +82,27 @@ func BGetEntry(timeoutInMilliseconds int, clientParams *BClientParams, userID, a return entry, nil } +func GetClientWithAutoConfig(ctx context.Context, clientParams BClientParams) (*grpcc.Client, error) { + // TODO(amarcedone) For now clientSecretFile is not needed as there is no authentication. Consider removing. + + cc, err := dial(clientParams.KtURL, clientParams.KtTLSCertPEM, "") + + if err != nil { + return nil, fmt.Errorf("Error Dialing %v: %v", clientParams.KtURL, err) + } + + ktClient := spb.NewKeyTransparencyServiceClient(cc) + + config, err := ktClient.GetDomainInfo(ctx, &tpb.GetDomainInfoRequest{}) + if err != nil { + return nil, fmt.Errorf("Error getting config: %v", err) + } + //return nil, fmt.Errorf("Error Dialing for AutoConfig3") + + return grpcc.NewFromConfig(cc, config) +} + + func GetClient(clientParams BClientParams, clientSecretFile string) (*grpcc.Client, error) { // TODO(amarcedone) For now clientSecretFile is not needed as there is no authentication. Consider removing. @@ -102,8 +133,11 @@ func GetClient(clientParams BClientParams, clientSecretFile string) (*grpcc.Clie return nil, fmt.Errorf("Error parsing vrf public key: %v", err) } - cli := pb.NewKeyTransparencyServiceClient(cc) - return grpcc.New(cli, vrfVerifier, verifier, log), nil + //cli := pb.NewKeyTransparencyServiceClient(cc) + //return grpcc.New(cli, vrfVerifier, verifier, log, true), nil + + //cc, vrfPub, mapPubKey, coniks.Default + return grpcc.New(cc, vrfVerifier, verifier, coniks.Default, log), nil } func dial(ktURL string, caPEM []byte, clientSecretFile string) (*grpc.ClientConn, error) { From fb3ae6e6c10bc3f5313e7ccda4cf6ab338877cb3 Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Tue, 22 Aug 2017 15:28:36 -0700 Subject: [PATCH 05/12] Add a list of client connection at the package level, indexed by ktURL --- core/client/gobindClient/client.go | 240 ++++++++++++----------------- 1 file changed, 100 insertions(+), 140 deletions(-) diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 239f7a7ef..5a5110f4f 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -5,70 +5,108 @@ import ( "context" "fmt" "github.com/google/keytransparency/cmd/keytransparency-client/grpcc" - "github.com/google/trillian" - "github.com/google/trillian/client" - "github.com/google/trillian/crypto/keys/pem" - "github.com/google/trillian/merkle/hashers" - _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered (needed by the bGetVerifierFromParams function) + _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered + _ "github.com/google/trillian/merkle/coniks" // Register coniks + "google.golang.org/grpc" "google.golang.org/grpc/credentials" "net" "time" - "crypto/tls" "crypto/x509" "github.com/google/keytransparency/core/client/kt" - "github.com/google/keytransparency/core/crypto/keymaster" - "github.com/google/keytransparency/core/crypto/vrf/p256" - spb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service" tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" + spb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service" + "bytes" + "github.com/benlaurie/objecthash/go/objecthash" + "io/ioutil" "log" - "github.com/google/trillian/merkle/coniks" ) -type BClientParams struct { - KtURL string - MapID int64 - KtTLSCertPEM []byte - VrfPubPEM []byte - KtSigPubKey []byte - LogPEM []byte +var ( + initialized bool + + clients map[string]*grpcc.Client = make(map[string]*grpcc.Client) + + timeout time.Duration + + // Vlog is the verbose logger. By default it outputs to /dev/null. + Vlog = log.New(ioutil.Discard, "", 0) +) + +func checkInitialized() error { + if initialized == false { + return fmt.Errorf("The keytransparency gobindClient has not been intialized yet. Please call init first.") + } + return nil } -// TODO(amarcedone) consider persisting the client or at least the trusted smr, to gain efficiency and stronger consistency guarantees. +func BInit(timeoutInMs int32) error { + if initialized { + fmt.Errorf("The library was already initialized.") + } + + initialized = true -func NewBClientParams(KtURL string, MapID int64, KtTLSCertPEM, VrfPubPEM, KtSigPubKey, LogPEM []byte) *BClientParams { - // Note: byte arrays need to be explicitly cloned due to some gobind limitations. - cKtTLSCertPEM := make([]byte, len(KtTLSCertPEM)) - copy(cKtTLSCertPEM, KtTLSCertPEM) - cVrfPubPEM := make([]byte, len(VrfPubPEM)) - copy(cVrfPubPEM, VrfPubPEM) - cKtSigPubKey := make([]byte, len(KtSigPubKey)) - copy(cKtSigPubKey, KtSigPubKey) - cLogPEM := make([]byte, len(LogPEM)) - copy(cLogPEM, LogPEM) + timeout = time.Duration(timeoutInMs) * time.Millisecond - return &BClientParams{KtURL, MapID, cKtTLSCertPEM, cVrfPubPEM, cKtSigPubKey, cLogPEM} + // TODO Persistence_path processing will go here. + + return nil } -func BGetEntry(timeoutInMilliseconds int, clientParams *BClientParams, userID, appID string) ([]byte, error) { +func BAddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInfoHash []byte) error { + if _, exists := clients[ktURL]; exists == true { + fmt.Errorf("The KtServer connection for %v already exists", ktURL) + } - //timeout := time.Duration(timeoutInMilliseconds) * time.Millisecond - //c, err := GetClient(*clientParams, "") + // TODO Add URL validation here. - timeout := time.Duration(700) * time.Millisecond - ctx, _ := context.WithTimeout(context.Background(), timeout) + cc, err := dial(ktURL, insecureTLS, ktTLSCertPEM) + if err != nil { + return fmt.Errorf("Error Dialing %v: %v", ktURL, err) + } + + ktClient := spb.NewKeyTransparencyServiceClient(cc) - //c, err := GetClient(*clientParams, "") - c, err := GetClientWithAutoConfig(ctx, *clientParams) + ctx, _ := context.WithTimeout(context.Background(), timeout) + config, err := ktClient.GetDomainInfo(ctx, &tpb.GetDomainInfoRequest{}) + if err != nil { + return fmt.Errorf("Error getting config: %v", err) + } + if len(domainInfoHash) == 0 { + Vlog.Print("Warning: no domainInfoHash provided. Key material from the server will be trusted.") + } else { + if got := objecthash.ObjectHash(config); bytes.Compare(got[:], domainInfoHash) != 0 { + return fmt.Errorf("The KtServer %v returned a domainInfoResponse inconsistent with the provided domainInfoHash") + } + } + client, err := grpcc.NewFromConfig(cc, config) if err != nil { - return nil, fmt.Errorf("GetEntry failed: error connecting: %v", err) + return fmt.Errorf("Error adding the KtServer: %v", err) } - entry, smr, err := c.GetEntry(ctx, userID, appID) + + clients[ktURL] = client + return nil +} + +func BGetEntry(ktURL, userID, appID string) ([]byte, error) { + + if err := checkInitialized(); err != nil { + return []byte{}, err + } + + client, exists := clients[ktURL] + if !exists { + fmt.Errorf("A connection to %v does not exists. Please call BAddKtServer first", ktURL) + } + + ctx, _ := context.WithTimeout(context.Background(), timeout) + entry, smr, err := client.GetEntry(ctx, userID, appID) if err != nil { return nil, fmt.Errorf("GetEntry failed: %v", err) } @@ -82,127 +120,49 @@ func BGetEntry(timeoutInMilliseconds int, clientParams *BClientParams, userID, a return entry, nil } -func GetClientWithAutoConfig(ctx context.Context, clientParams BClientParams) (*grpcc.Client, error) { - // TODO(amarcedone) For now clientSecretFile is not needed as there is no authentication. Consider removing. - - cc, err := dial(clientParams.KtURL, clientParams.KtTLSCertPEM, "") - - if err != nil { - return nil, fmt.Errorf("Error Dialing %v: %v", clientParams.KtURL, err) - } - - ktClient := spb.NewKeyTransparencyServiceClient(cc) - - config, err := ktClient.GetDomainInfo(ctx, &tpb.GetDomainInfoRequest{}) - if err != nil { - return nil, fmt.Errorf("Error getting config: %v", err) - } - //return nil, fmt.Errorf("Error Dialing for AutoConfig3") - - return grpcc.NewFromConfig(cc, config) -} - +func dial(ktURL string, insecureTLS bool, ktTLSCertPEM []byte) (*grpc.ClientConn, error) { -func GetClient(clientParams BClientParams, clientSecretFile string) (*grpcc.Client, error) { - // TODO(amarcedone) For now clientSecretFile is not needed as there is no authentication. Consider removing. + creds, err := transportCreds(ktURL, insecureTLS, ktTLSCertPEM) - cc, err := dial(clientParams.KtURL, clientParams.KtTLSCertPEM, clientSecretFile) + cc, err := grpc.Dial(ktURL, grpc.WithTransportCredentials(creds)) if err != nil { - return nil, fmt.Errorf("Error Dialing %v: %v", clientParams.KtURL, err) - } - - // Log verifier. - logPubKey, err := pem.UnmarshalPublicKey(string(clientParams.LogPEM)) - if err != nil { - return nil, fmt.Errorf("Failed to open public key %v: %v", string(clientParams.LogPEM), err) - } - - hasher, err := hashers.NewLogHasher(trillian.HashStrategy_OBJECT_RFC6962_SHA256) - if err != nil { - return nil, fmt.Errorf("Failed retrieving LogHasher from registry: %v", err) + return nil, err } - log := client.NewLogVerifier(hasher, logPubKey) + return cc, nil +} - verifier, err := keymaster.NewVerifierFromPEM(clientParams.KtSigPubKey) - if err != nil { - return nil, fmt.Errorf("Error creating verifier from PEM encoded key: %v", err) - } +func transportCreds(ktURL string, insecure bool, ktTLSCertPEM []byte) (credentials.TransportCredentials, error) { - vrfVerifier, err := p256.NewVRFVerifierFromPEM(clientParams.VrfPubPEM) + host, _, err := net.SplitHostPort(ktURL) if err != nil { - return nil, fmt.Errorf("Error parsing vrf public key: %v", err) + return nil, err } - //cli := pb.NewKeyTransparencyServiceClient(cc) - //return grpcc.New(cli, vrfVerifier, verifier, log, true), nil + switch { + case insecure: // Impatient insecure. + return credentials.NewTLS(&tls.Config{ + InsecureSkipVerify: true, + }), nil - //cc, vrfPub, mapPubKey, coniks.Default - return grpcc.New(cc, vrfVerifier, verifier, coniks.Default, log), nil -} - -func dial(ktURL string, caPEM []byte, clientSecretFile string) (*grpc.ClientConn, error) { - // TODO(amarcedone) For now clientSecretFile is not needed as there is no authentication. Consider removing. - - var opts []grpc.DialOption - // TODO(amarcedone) Copied from root.go. Figure out why we have "if true" here. Perhaps for scope? - if true { - host, _, err := net.SplitHostPort(ktURL) - if err != nil { - return nil, err - } - var creds credentials.TransportCredentials - if len(caPEM) != 0 { - var err error - cp := x509.NewCertPool() - if !cp.AppendCertsFromPEM(caPEM) { - return nil, fmt.Errorf("credentials: failed to append certificates") - } - creds, err = credentials.NewTLS(&tls.Config{ServerName: host, RootCAs: cp}), nil - if err != nil { - return nil, err - } - } else { - // Use the local set of root certs. - creds = credentials.NewClientTLSFromCert(nil, host) + case len(ktTLSCertPEM) != 0: // Custom CA Cert. + cp := x509.NewCertPool() + if !cp.AppendCertsFromPEM(ktTLSCertPEM) { + return nil, fmt.Errorf("credentials: failed to append certificates") } - opts = append(opts, grpc.WithTransportCredentials(creds)) - } - - // AUTHENTICATION is not needed for gobind clients as they only perform get requests. - //// Add authentication information for the grpc. Only one type of credential - //// should exist in an RPC call. Fake credentials have the highest priority, followed - //// by Client credentials and Service Credentials. - //fakeUserID := viper.GetString("fake-auth-userid") - //switch { - //case fakeUserID != "": - // opts = append(opts, grpc.WithPerRPCCredentials( - // authentication.GetFakeCredential(fakeUserID))) - //case clientSecretFile != "": - // creds, err := getCreds(clientSecretFile) - // if err != nil { - // return nil, err - // } - // opts = append(opts, grpc.WithPerRPCCredentials(creds)) - //case serviceKeyFile != "": - // creds, err := getServiceCreds(serviceKeyFile) - // if err != nil { - // return nil, err - // } - // opts = append(opts, grpc.WithPerRPCCredentials(creds)) - //} + creds := credentials.NewTLS(&tls.Config{ServerName: host, RootCAs: cp}) + return creds, nil - cc, err := grpc.Dial(ktURL, opts...) - if err != nil { - return nil, err + default: // Use the local set of root certs. + return credentials.NewClientTLSFromCert(nil, host), nil } - return cc, nil } func BSetCustomLogger(writer BWriter) { kt.Vlog = log.New(writer, "", log.Lshortfile) + Vlog = log.New(writer, "", log.Lshortfile) } // Local copy of io.Writer interface used to redirect logs. type BWriter interface { Write(p []byte) (n int, err error) -} \ No newline at end of file +} From 608543341936b25accb58ce68f2958b348eb540d Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Wed, 23 Aug 2017 08:52:59 -0700 Subject: [PATCH 06/12] Revert changes to verify.go, which are not needed at the moment --- core/client/kt/verify.go | 81 +--------------------------------------- 1 file changed, 2 insertions(+), 79 deletions(-) diff --git a/core/client/kt/verify.go b/core/client/kt/verify.go index 768424789..d11d0e290 100644 --- a/core/client/kt/verify.go +++ b/core/client/kt/verify.go @@ -23,21 +23,17 @@ import ( "log" "github.com/google/keytransparency/core/crypto/commitments" - "github.com/google/keytransparency/core/crypto/keymaster" "github.com/google/keytransparency/core/crypto/vrf" - "github.com/google/keytransparency/core/crypto/vrf/p256" - tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" "github.com/golang/protobuf/proto" "github.com/google/trillian" "github.com/google/trillian/client" tcrypto "github.com/google/trillian/crypto" - "github.com/google/trillian/crypto/keys/pem" "github.com/google/trillian/merkle" "github.com/google/trillian/merkle/hashers" - "github.com/google/trillian/merkle/maphasher" - _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered (needed by the bGetVerifierFromParams function) "golang.org/x/net/context" + + tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" ) var ( @@ -152,76 +148,3 @@ func (v *Verifier) VerifyGetEntryResponse(ctx context.Context, userID, appID str Vlog.Printf("✓ Log inclusion proof verified.") return nil } - -type BVerifierParams struct { - MapID int64 - VrfPubPEM []byte - KtPEM []byte - LogPEM []byte -} - -func NewBVerifierParams(MapID int64, VrfPubPEM, KtPEM, LogPEM []byte) *BVerifierParams { - // Note: byte arrays need to be explicitly cloned due to some gobind limitations. - cVrfPubPEM := make([]byte, len(VrfPubPEM)) - copy(cVrfPubPEM, VrfPubPEM) - cKtPEM := make([]byte, len(KtPEM)) - copy(cKtPEM, KtPEM) - cLogPEM := make([]byte, len(LogPEM)) - copy(cLogPEM, LogPEM) - - return &BVerifierParams{MapID, cVrfPubPEM, cKtPEM, cLogPEM} -} - -func bGetVerifierFromParams(p BVerifierParams) (*Verifier, error) { - - vrf, err := p256.NewVRFVerifierFromPEM(p.VrfPubPEM) - if err != nil { - return nil, fmt.Errorf("Error parsing vrf public key: %v", err) - } - - // TODO this maphasher implementation is ok for debug only. Update. - maphasher := maphasher.Default - - // Verifier - ver, err := keymaster.NewVerifierFromPEM(p.KtPEM) - if err != nil { - return nil, fmt.Errorf("Error creating verifier from PEM encoded key: %v", err) - } - - // log can verify Trillian Logs. - logPubKey, err := pem.UnmarshalPublicKey(string(p.LogPEM)) - if err != nil { - return nil, fmt.Errorf("Failed to open public key %v: %v", logPubKey, err) - } - hasher, 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) - - return New(vrf, maphasher, ver, log), nil -} - -func BVerifyGetEntryResponse(verParam *BVerifierParams, userID string, appID string, - trusted_trillianSignedLogRoot []byte, in_tpbGetEntryResponse []byte) error { - - v, err := bGetVerifierFromParams(*verParam) - if err != nil { - return fmt.Errorf("Couldn't build verifier: %v", err) - } - - trusted := &trillian.SignedLogRoot{} - err = proto.Unmarshal(trusted_trillianSignedLogRoot, trusted) - if err != nil { - return err - } - - in := &tpb.GetEntryResponse{} - err = proto.Unmarshal(in_tpbGetEntryResponse, in) - if err != nil { - return err - } - - // TODO(amarcedone) Is context.Background() appropriate here? - return v.VerifyGetEntryResponse(context.Background(), userID, appID, trusted, in) -} From d5344686254b469c69b45c391a929da190d6635d Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Wed, 23 Aug 2017 09:00:27 -0700 Subject: [PATCH 07/12] Add a warning to the logs when TLS cert validation is skipped by the gobindClient --- core/client/gobindClient/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 5a5110f4f..33ab6d965 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -5,8 +5,8 @@ import ( "context" "fmt" "github.com/google/keytransparency/cmd/keytransparency-client/grpcc" - _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered _ "github.com/google/trillian/merkle/coniks" // Register coniks + _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered "google.golang.org/grpc" "google.golang.org/grpc/credentials" @@ -140,6 +140,7 @@ func transportCreds(ktURL string, insecure bool, ktTLSCertPEM []byte) (credentia switch { case insecure: // Impatient insecure. + Vlog.Printf("Warning: Skipping verification of KT Server's TLS certificate.") return credentials.NewTLS(&tls.Config{ InsecureSkipVerify: true, }), nil From 2aa81d372562707fdd1275c9889331f181dfc1b1 Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Wed, 23 Aug 2017 09:38:09 -0700 Subject: [PATCH 08/12] Reorganized import --- core/client/gobindClient/client.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 33ab6d965..2c9cfa42e 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -2,27 +2,27 @@ package gobindClient import ( + "bytes" "context" + "crypto/tls" + "crypto/x509" "fmt" + "io/ioutil" + "log" + "net" + "time" + "github.com/google/keytransparency/cmd/keytransparency-client/grpcc" - _ "github.com/google/trillian/merkle/coniks" // Register coniks - _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered + "github.com/google/keytransparency/core/client/kt" + "github.com/benlaurie/objecthash/go/objecthash" "google.golang.org/grpc" "google.golang.org/grpc/credentials" - "net" - "time" - "crypto/tls" - "crypto/x509" - "github.com/google/keytransparency/core/client/kt" tpb "github.com/google/keytransparency/core/proto/keytransparency_v1_types" spb "github.com/google/keytransparency/impl/proto/keytransparency_v1_service" - - "bytes" - "github.com/benlaurie/objecthash/go/objecthash" - "io/ioutil" - "log" + _ "github.com/google/trillian/merkle/coniks" // Register coniks + _ "github.com/google/trillian/merkle/objhasher" // Used to init the package so that the hasher gets registered ) var ( @@ -95,7 +95,7 @@ func BAddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInf } func BGetEntry(ktURL, userID, appID string) ([]byte, error) { - + log.Println("AXAX test logs.") if err := checkInitialized(); err != nil { return []byte{}, err } From 22e09da48d9ea792365e1a3bc791719c2bb31a07 Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Wed, 23 Aug 2017 09:52:15 -0700 Subject: [PATCH 09/12] Removed initialization. Minor nits. --- core/client/gobindClient/client.go | 38 ++++++------------------------ 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 2c9cfa42e..018357497 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -26,38 +26,19 @@ import ( ) var ( - initialized bool - clients map[string]*grpcc.Client = make(map[string]*grpcc.Client) - timeout time.Duration + timeout time.Duration = time.Duration(500) * time.Millisecond // Vlog is the verbose logger. By default it outputs to /dev/null. Vlog = log.New(ioutil.Discard, "", 0) ) -func checkInitialized() error { - if initialized == false { - return fmt.Errorf("The keytransparency gobindClient has not been intialized yet. Please call init first.") - } - return nil +func SetTimeout(ms int32){ + timeout = time.Duration(ms) * time.Millisecond } -func BInit(timeoutInMs int32) error { - if initialized { - fmt.Errorf("The library was already initialized.") - } - - initialized = true - - timeout = time.Duration(timeoutInMs) * time.Millisecond - - // TODO Persistence_path processing will go here. - - return nil -} - -func BAddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInfoHash []byte) error { +func AddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInfoHash []byte) error { if _, exists := clients[ktURL]; exists == true { fmt.Errorf("The KtServer connection for %v already exists", ktURL) } @@ -94,12 +75,7 @@ func BAddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInf return nil } -func BGetEntry(ktURL, userID, appID string) ([]byte, error) { - log.Println("AXAX test logs.") - if err := checkInitialized(); err != nil { - return []byte{}, err - } - +func GetEntry(ktURL, userID, appID string) ([]byte, error) { client, exists := clients[ktURL] if !exists { fmt.Errorf("A connection to %v does not exists. Please call BAddKtServer first", ktURL) @@ -158,12 +134,12 @@ func transportCreds(ktURL string, insecure bool, ktTLSCertPEM []byte) (credentia } } -func BSetCustomLogger(writer BWriter) { +func SetCustomLogger(writer LogWriter) { kt.Vlog = log.New(writer, "", log.Lshortfile) Vlog = log.New(writer, "", log.Lshortfile) } // Local copy of io.Writer interface used to redirect logs. -type BWriter interface { +type LogWriter interface { Write(p []byte) (n int, err error) } From 1b8173b33d076e2eff6f04f098c312117504af51 Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Wed, 23 Aug 2017 16:01:23 -0400 Subject: [PATCH 10/12] Restructured logging. When using gobindClient, Verbose log goes to logcat, as well as standard log. Optionally, vlog can be redirected to a custom java writer --- core/client/gobindClient/client.go | 19 ++------ core/client/gobindClient/multiLog.go | 65 ++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 core/client/gobindClient/multiLog.go diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 018357497..850bac26e 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -7,13 +7,11 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "io/ioutil" "log" "net" "time" "github.com/google/keytransparency/cmd/keytransparency-client/grpcc" - "github.com/google/keytransparency/core/client/kt" "github.com/benlaurie/objecthash/go/objecthash" "google.golang.org/grpc" @@ -30,11 +28,10 @@ var ( timeout time.Duration = time.Duration(500) * time.Millisecond - // Vlog is the verbose logger. By default it outputs to /dev/null. - Vlog = log.New(ioutil.Discard, "", 0) + Vlog = log.New(&multiLogWriter, "", log.LstdFlags) ) -func SetTimeout(ms int32){ +func SetTimeout(ms int32) { timeout = time.Duration(ms) * time.Millisecond } @@ -124,7 +121,7 @@ func transportCreds(ktURL string, insecure bool, ktTLSCertPEM []byte) (credentia case len(ktTLSCertPEM) != 0: // Custom CA Cert. cp := x509.NewCertPool() if !cp.AppendCertsFromPEM(ktTLSCertPEM) { - return nil, fmt.Errorf("credentials: failed to append certificates") + return nil, fmt.Errorf("Failed to append certificates") } creds := credentials.NewTLS(&tls.Config{ServerName: host, RootCAs: cp}) return creds, nil @@ -133,13 +130,3 @@ func transportCreds(ktURL string, insecure bool, ktTLSCertPEM []byte) (credentia return credentials.NewClientTLSFromCert(nil, host), nil } } - -func SetCustomLogger(writer LogWriter) { - kt.Vlog = log.New(writer, "", log.Lshortfile) - Vlog = log.New(writer, "", log.Lshortfile) -} - -// Local copy of io.Writer interface used to redirect logs. -type LogWriter interface { - Write(p []byte) (n int, err error) -} diff --git a/core/client/gobindClient/multiLog.go b/core/client/gobindClient/multiLog.go new file mode 100644 index 000000000..4c4660a60 --- /dev/null +++ b/core/client/gobindClient/multiLog.go @@ -0,0 +1,65 @@ +package gobindClient + +import ( + "errors" + "fmt" + "io" + "log" + "os" + + "github.com/google/keytransparency/core/client/kt" +) + +var multiLogWriter = MultiIoWriter{[]io.Writer{os.Stderr}} + +func init() { + kt.Vlog = log.New(&multiLogWriter, "", log.LstdFlags) +} + +// Local copy of io.Writer interface which can be implemented in Java. Used to redirect logs. +type LogWriter interface { + Write(p []byte) (n int, err error) +} + +type MultiIoWriter struct { + writers []io.Writer +} + +func (m *MultiIoWriter) Write(p []byte) (n int, err error) { + if len(m.writers) == 0 { + return 0, fmt.Errorf("Tried to use a MultiIoWriter which does not contain any writers") + } + multiError := "" + minBytesWritten := len(p) + log.Printf("There are %v writers", len(m.writers)) + for i, w := range m.writers { + log.Printf("Write to %v made", i) + n, err = w.Write(p) + if err != nil { + multiError = multiError + fmt.Sprintf("%v bytes written to %v: %v", n, w, err) + } + minBytesWritten = min(n, minBytesWritten) + } + + return minBytesWritten, errors.New(multiError) +} + +func (m *MultiIoWriter) AddWriter(w io.Writer) { + if m.writers == nil { + m.writers = []io.Writer{} + } + log.Printf("Added writer: %v", w) + m.writers = append(m.writers, w) + log.Printf("New size: %v", len(m.writers)) +} + +func min(a, b int) int { + if a <= b { + return a + } + return b +} + +func AddVerboseLogsDestination(writer LogWriter) { + multiLogWriter.AddWriter(writer) +} From 0b1ae8c8e2fb1211ba4f228a4bdf568cd96b8131 Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Wed, 23 Aug 2017 18:05:07 -0400 Subject: [PATCH 11/12] Address review comments and make check issues --- core/client/gobindClient/client.go | 68 +++++++++++++++++++++----- core/client/gobindClient/multiLog.go | 65 ------------------------ core/client/multiWriter/multiWriter.go | 65 ++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 76 deletions(-) delete mode 100644 core/client/gobindClient/multiLog.go create mode 100644 core/client/multiWriter/multiWriter.go diff --git a/core/client/gobindClient/client.go b/core/client/gobindClient/client.go index 850bac26e..ca7ad873d 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindClient/client.go @@ -1,6 +1,23 @@ -// TODO(amarcedone) : rename package to gobind_client after https://github.com/golang/go/issues/17359 is solved. +// Copyright 2016 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 gobindClient contains a gobind friendly implementation of a KeyTransparency Client able to make +// GetEntry requests to a KT server and verify the soundness of the responses. package gobindClient +// TODO(amarcedone) : rename package to gobind_client after https://github.com/golang/go/issues/17359 is solved. + import ( "bytes" "context" @@ -9,9 +26,12 @@ import ( "fmt" "log" "net" + "os" "time" "github.com/google/keytransparency/cmd/keytransparency-client/grpcc" + "github.com/google/keytransparency/core/client/kt" + "github.com/google/keytransparency/core/client/multiWriter" "github.com/benlaurie/objecthash/go/objecthash" "google.golang.org/grpc" @@ -24,20 +44,40 @@ import ( ) var ( - clients map[string]*grpcc.Client = make(map[string]*grpcc.Client) + clients = make(map[string]*grpcc.Client) + + timeout = 500 * time.Millisecond - timeout time.Duration = time.Duration(500) * time.Millisecond + multiLogWriter = multiWriter.New(os.Stderr) - Vlog = log.New(&multiLogWriter, "", log.LstdFlags) + // Vlog is the verbose logger. By default it outputs to stderr (logcat on Android), but other destination can be + // added through the AddVerboseLogsDestination method. + Vlog = log.New(multiLogWriter, "", log.LstdFlags) ) +func init() { + kt.Vlog = log.New(multiLogWriter, "", log.LstdFlags) +} + +// AddVerboseLogsDestination instructs the logger of the gobindClient package to also write all log statements to the provided writer. +func AddVerboseLogsDestination(writer LogWriter) { + multiLogWriter.AddWriter(writer) +} + +// LogWriter is a local copy of the io.Writer interface which can be implemented in Java. Used to redirect logs. +type LogWriter interface { + Write(p []byte) (n int, err error) +} + +// SetTimeout sets the timeout (in milliseconds) used for all rpc network requests. func SetTimeout(ms int32) { timeout = time.Duration(ms) * time.Millisecond } +// AddKtServer creates a new grpc client to handle connections to the ktURL server and adds it to the global map of clients. func AddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInfoHash []byte) error { - if _, exists := clients[ktURL]; exists == true { - fmt.Errorf("The KtServer connection for %v already exists", ktURL) + if _, exists := clients[ktURL]; exists { + return fmt.Errorf("The KtServer connection for %v already exists", ktURL) } // TODO Add URL validation here. @@ -49,7 +89,8 @@ func AddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInfo ktClient := spb.NewKeyTransparencyServiceClient(cc) - ctx, _ := context.WithTimeout(context.Background(), timeout) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() config, err := ktClient.GetDomainInfo(ctx, &tpb.GetDomainInfoRequest{}) if err != nil { return fmt.Errorf("Error getting config: %v", err) @@ -58,8 +99,8 @@ func AddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInfo if len(domainInfoHash) == 0 { Vlog.Print("Warning: no domainInfoHash provided. Key material from the server will be trusted.") } else { - if got := objecthash.ObjectHash(config); bytes.Compare(got[:], domainInfoHash) != 0 { - return fmt.Errorf("The KtServer %v returned a domainInfoResponse inconsistent with the provided domainInfoHash") + if got := objecthash.ObjectHash(config); !bytes.Equal(got[:], domainInfoHash) { + return fmt.Errorf("The KtServer %v returned a domainInfoResponse inconsistent with the provided domainInfoHash", ktURL) } } @@ -72,13 +113,15 @@ func AddKtServer(ktURL string, insecureTLS bool, ktTLSCertPEM []byte, domainInfo return nil } +// GetEntry retrieves an entry from the ktURL server and verifies the soundness of the corresponding proofs. func GetEntry(ktURL, userID, appID string) ([]byte, error) { client, exists := clients[ktURL] if !exists { - fmt.Errorf("A connection to %v does not exists. Please call BAddKtServer first", ktURL) + return nil, fmt.Errorf("A connection to %v does not exists. Please call BAddKtServer first", ktURL) } - ctx, _ := context.WithTimeout(context.Background(), timeout) + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() entry, smr, err := client.GetEntry(ctx, userID, appID) if err != nil { return nil, fmt.Errorf("GetEntry failed: %v", err) @@ -96,6 +139,9 @@ func GetEntry(ktURL, userID, appID string) ([]byte, error) { func dial(ktURL string, insecureTLS bool, ktTLSCertPEM []byte) (*grpc.ClientConn, error) { creds, err := transportCreds(ktURL, insecureTLS, ktTLSCertPEM) + if err != nil { + return nil, err + } cc, err := grpc.Dial(ktURL, grpc.WithTransportCredentials(creds)) if err != nil { diff --git a/core/client/gobindClient/multiLog.go b/core/client/gobindClient/multiLog.go deleted file mode 100644 index 4c4660a60..000000000 --- a/core/client/gobindClient/multiLog.go +++ /dev/null @@ -1,65 +0,0 @@ -package gobindClient - -import ( - "errors" - "fmt" - "io" - "log" - "os" - - "github.com/google/keytransparency/core/client/kt" -) - -var multiLogWriter = MultiIoWriter{[]io.Writer{os.Stderr}} - -func init() { - kt.Vlog = log.New(&multiLogWriter, "", log.LstdFlags) -} - -// Local copy of io.Writer interface which can be implemented in Java. Used to redirect logs. -type LogWriter interface { - Write(p []byte) (n int, err error) -} - -type MultiIoWriter struct { - writers []io.Writer -} - -func (m *MultiIoWriter) Write(p []byte) (n int, err error) { - if len(m.writers) == 0 { - return 0, fmt.Errorf("Tried to use a MultiIoWriter which does not contain any writers") - } - multiError := "" - minBytesWritten := len(p) - log.Printf("There are %v writers", len(m.writers)) - for i, w := range m.writers { - log.Printf("Write to %v made", i) - n, err = w.Write(p) - if err != nil { - multiError = multiError + fmt.Sprintf("%v bytes written to %v: %v", n, w, err) - } - minBytesWritten = min(n, minBytesWritten) - } - - return minBytesWritten, errors.New(multiError) -} - -func (m *MultiIoWriter) AddWriter(w io.Writer) { - if m.writers == nil { - m.writers = []io.Writer{} - } - log.Printf("Added writer: %v", w) - m.writers = append(m.writers, w) - log.Printf("New size: %v", len(m.writers)) -} - -func min(a, b int) int { - if a <= b { - return a - } - return b -} - -func AddVerboseLogsDestination(writer LogWriter) { - multiLogWriter.AddWriter(writer) -} diff --git a/core/client/multiWriter/multiWriter.go b/core/client/multiWriter/multiWriter.go new file mode 100644 index 000000000..d4b933c7d --- /dev/null +++ b/core/client/multiWriter/multiWriter.go @@ -0,0 +1,65 @@ +// Copyright 2016 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 multiWriter + +import ( + "errors" + "fmt" + "io" +) + +// MultiWriter contains a list of io.Writer objects. Its Write method tries to write to all of them, and aggregates +// the errors (if any of the write call fails). +type MultiWriter interface { + AddWriter(w io.Writer) + Write(p []byte) (n int, err error) +} + +// New returns an implementation of the MultiWriter interface +func New(w io.Writer) MultiWriter { + return &multiIoWriter{[]io.Writer{w}} +} + +type multiIoWriter struct { + writers []io.Writer +} + +func (m *multiIoWriter) Write(p []byte) (n int, err error) { + if len(m.writers) == 0 { + return 0, fmt.Errorf("Tried to use a MultiIoWriter which does not contain any writers") + } + multiError := "" + minBytesWritten := len(p) + for _, w := range m.writers { + n, err = w.Write(p) + if err != nil { + multiError = multiError + fmt.Sprintf("%v bytes written to %v: %v", n, w, err) + } + minBytesWritten = min(n, minBytesWritten) + } + + return minBytesWritten, errors.New(multiError) +} + +func (m *multiIoWriter) AddWriter(w io.Writer) { + m.writers = append(m.writers, w) +} + +func min(a, b int) int { + if a <= b { + return a + } + return b +} From 92734f411d6a2908fba8120c5f3db1f947b1e40d Mon Sep 17 00:00:00 2001 From: AMarcedone Date: Wed, 23 Aug 2017 18:13:46 -0400 Subject: [PATCH 12/12] Capitalize gobindclient --- core/client/{gobindClient => gobindclient}/client.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) rename core/client/{gobindClient => gobindclient}/client.go (95%) diff --git a/core/client/gobindClient/client.go b/core/client/gobindclient/client.go similarity index 95% rename from core/client/gobindClient/client.go rename to core/client/gobindclient/client.go index ca7ad873d..e24670549 100644 --- a/core/client/gobindClient/client.go +++ b/core/client/gobindclient/client.go @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package gobindClient contains a gobind friendly implementation of a KeyTransparency Client able to make +// Package gobindclient contains a gobind friendly implementation of a KeyTransparency Client able to make // GetEntry requests to a KT server and verify the soundness of the responses. -package gobindClient - -// TODO(amarcedone) : rename package to gobind_client after https://github.com/golang/go/issues/17359 is solved. +package gobindclient import ( "bytes" @@ -59,7 +57,7 @@ func init() { kt.Vlog = log.New(multiLogWriter, "", log.LstdFlags) } -// AddVerboseLogsDestination instructs the logger of the gobindClient package to also write all log statements to the provided writer. +// AddVerboseLogsDestination instructs the logger of the gobindclient package to also write all log statements to the provided writer. func AddVerboseLogsDestination(writer LogWriter) { multiLogWriter.AddWriter(writer) }