From 13b577e805456fb649d553debb7ef1cc583f14f4 Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Fri, 6 Sep 2024 10:34:38 +0000 Subject: [PATCH 01/10] remove private key from config --- personalities/sctfe/config.go | 23 +-- personalities/sctfe/config_test.go | 150 ++++++--------- personalities/sctfe/configpb/config.pb.go | 223 ++++++++++------------ personalities/sctfe/configpb/config.proto | 3 - personalities/sctfe/ct_server_gcp/main.go | 8 +- personalities/sctfe/instance.go | 16 +- personalities/sctfe/instance_test.go | 129 +++++-------- 7 files changed, 221 insertions(+), 331 deletions(-) diff --git a/personalities/sctfe/config.go b/personalities/sctfe/config.go index d6ca175e..359cdf14 100644 --- a/personalities/sctfe/config.go +++ b/personalities/sctfe/config.go @@ -27,16 +27,15 @@ import ( "github.com/transparency-dev/trillian-tessera/personalities/sctfe/configpb" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" "k8s.io/klog/v2" ) // ValidatedLogConfig represents the LogConfig with the information that has // been successfully parsed as a result of validating it. type ValidatedLogConfig struct { - Config *LogConfig - PubKey crypto.PublicKey - PrivKey proto.Message + Config *LogConfig + PubKey crypto.PublicKey + Signer crypto.Signer // If set, ExtKeyUsages will restrict the set of such usages that the // server will accept. By default all are accepted. The values specified // must be ones known to the x509 package. @@ -54,8 +53,6 @@ type LogConfig struct { // Path to the file containing root certificates that are acceptable to the // log. The certs are served through get-roots endpoint. RootsPemFile string - // The private key used for signing Checkpoints or SCTs. - PrivateKey *anypb.Any // The public key matching the above private key (if both are present). // It can be specified for the convenience of test tools, but it not used // by the server. @@ -98,7 +95,7 @@ func LogConfigFromFile(filename string) (*configpb.LogConfig, error) { // - Merge delays (if present) are correct. // // Returns the validated structures (useful to avoid double validation). -func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, bucket string, spannerDB string, rootsPemFile string, rejectExpired bool, rejectUnexpired bool, extKeyUsages string, rejectExtensions string, notAfterStart *time.Time, notAfterLimit *time.Time) (*ValidatedLogConfig, error) { +func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, bucket string, spannerDB string, rootsPemFile string, rejectExpired bool, rejectUnexpired bool, extKeyUsages string, rejectExtensions string, notAfterStart *time.Time, notAfterLimit *time.Time, signer crypto.Signer) (*ValidatedLogConfig, error) { if origin == "" { return nil, errors.New("empty origin") } @@ -129,7 +126,6 @@ func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, Config: &LogConfig{ Origin: origin, RootsPemFile: rootsPemFile, - PrivateKey: cfg.PrivateKey, PublicKey: cfg.PublicKey, RejectExpired: rejectExpired, RejectUnexpired: rejectUnexpired, @@ -137,6 +133,7 @@ func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, }, NotAfterStart: notAfterStart, NotAfterLimit: notAfterLimit, + Signer: signer, } // Validate the public key. @@ -147,16 +144,6 @@ func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, } } - // Validate the private key. - if cfg.PrivateKey == nil { - return nil, errors.New("empty private key") - } - privKey, err := cfg.PrivateKey.UnmarshalNew() - if err != nil { - return nil, fmt.Errorf("invalid private key: %v", err) - } - vCfg.PrivKey = privKey - if rejectExpired && rejectUnexpired { return nil, errors.New("rejecting all certificates") } diff --git a/personalities/sctfe/config_test.go b/personalities/sctfe/config_test.go index bd6373dd..65206d23 100644 --- a/personalities/sctfe/config_test.go +++ b/personalities/sctfe/config_test.go @@ -15,12 +15,13 @@ package sctfe import ( + "crypto" "fmt" "strings" "testing" "time" - "github.com/google/trillian/crypto/keyspb" + "github.com/google/trillian/crypto/keys/pem" "github.com/transparency-dev/trillian-tessera/personalities/sctfe/configpb" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" @@ -35,7 +36,10 @@ func mustMarshalAny(pb proto.Message) *anypb.Any { } func TestValidateLogConfig(t *testing.T) { - privKey := mustMarshalAny(&keyspb.PEMKeyFile{Path: "../testdata/ct-http-server.privkey.pem", Password: "dirk"}) + signer, err := pem.ReadPrivateKeyFile("./testdata/ct-http-server.privkey.pem", "dirk") + if err != nil { + t.Fatalf("Can't open key: %v", err) + } t100 := time.Unix(100, 0) t200 := time.Unix(200, 0) @@ -53,6 +57,7 @@ func TestValidateLogConfig(t *testing.T) { extKeyUsages string notAfterStart *time.Time notAfterLimit *time.Time + signer crypto.Signer }{ { desc: "empty-origin", @@ -63,192 +68,145 @@ func TestValidateLogConfig(t *testing.T) { spannerDB: "spanner", }, { - desc: "empty-private-key", - wantErr: "empty private key", + desc: "empty-projectID", + wantErr: "empty projectID", cfg: &configpb.LogConfig{}, origin: "testlog", - projectID: "project", - bucket: "bucket", - spannerDB: "spanner", - }, - { - desc: "invalid-private-key", - wantErr: "invalid private key", - cfg: &configpb.LogConfig{ - PrivateKey: &anypb.Any{}, - }, - origin: "testlog", - projectID: "project", - bucket: "bucket", - spannerDB: "spanner", - }, - { - desc: "empty-projectID", - wantErr: "empty projectID", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, - origin: "testlog", projectID: "", bucket: "bucket", spannerDB: "spanner", + signer: signer, }, { - desc: "empty-bucket", - wantErr: "empty bucket", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "empty-bucket", + wantErr: "empty bucket", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "", spannerDB: "spanner", + signer: signer, }, { - desc: "empty-spannerDB", - wantErr: "empty spannerDB", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "empty-spannerDB", + wantErr: "empty spannerDB", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "", + signer: signer, }, { - desc: "rejecting-all", - wantErr: "rejecting all certificates", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "rejecting-all", + wantErr: "rejecting all certificates", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", rejectExpired: true, rejectUnexpired: true, + signer: signer, }, { - desc: "unknown-ext-key-usage-1", - wantErr: "unknown extended key usage", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "unknown-ext-key-usage-1", + wantErr: "unknown extended key usage", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", extKeyUsages: "wrong_usage", + signer: signer, }, { - desc: "unknown-ext-key-usage-2", - wantErr: "unknown extended key usage", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "unknown-ext-key-usage-2", + wantErr: "unknown extended key usage", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", extKeyUsages: "ClientAuth,ServerAuth,TimeStomping", + signer: signer, }, { - desc: "unknown-ext-key-usage-3", - wantErr: "unknown extended key usage", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "unknown-ext-key-usage-3", + wantErr: "unknown extended key usage", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", extKeyUsages: "Any ", + signer: signer, }, { - desc: "limit-before-start", - wantErr: "limit before start", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "limit-before-start", + wantErr: "limit before start", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", notAfterStart: &t200, notAfterLimit: &t100, + signer: signer, }, { - desc: "ok", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, - origin: "testlog", - projectID: "project", - bucket: "bucket", - spannerDB: "spanner", - }, - { - // Note: Substituting an arbitrary proto.Message as a PrivateKey will not - // fail the validation because the actual key loading happens at runtime. - // TODO(pavelkalinnikov): Decouple key protos validation and loading, and - // make this test fail. - desc: "ok-not-a-key", - cfg: &configpb.LogConfig{ - PrivateKey: mustMarshalAny(&configpb.LogConfig{}), - }, + desc: "ok", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", + signer: signer, }, { - desc: "ok-ext-key-usages", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "ok-ext-key-usages", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", extKeyUsages: "ServerAuth,ClientAuth,OCSPSigning", + signer: signer, }, { - desc: "ok-start-timestamp", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "ok-start-timestamp", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", notAfterStart: &t100, + signer: signer, }, { - desc: "ok-limit-timestamp", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "ok-limit-timestamp", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", notAfterStart: &t200, + signer: signer, }, { - desc: "ok-range-timestamp", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "ok-range-timestamp", + cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", spannerDB: "spanner", notAfterStart: &t100, notAfterLimit: &t200, + signer: signer, }, } { t.Run(tc.desc, func(t *testing.T) { - vc, err := ValidateLogConfig(tc.cfg, tc.origin, tc.projectID, tc.bucket, tc.spannerDB, "", tc.rejectExpired, tc.rejectUnexpired, tc.extKeyUsages, "", tc.notAfterStart, tc.notAfterLimit) + vc, err := ValidateLogConfig(tc.cfg, tc.origin, tc.projectID, tc.bucket, tc.spannerDB, "", tc.rejectExpired, tc.rejectUnexpired, tc.extKeyUsages, "", tc.notAfterStart, tc.notAfterLimit, signer) if len(tc.wantErr) == 0 && err != nil { t.Errorf("ValidateLogConfig()=%v, want nil", err) } diff --git a/personalities/sctfe/configpb/config.pb.go b/personalities/sctfe/configpb/config.pb.go index 6bc0e09e..4303de6f 100644 --- a/personalities/sctfe/configpb/config.pb.go +++ b/personalities/sctfe/configpb/config.pb.go @@ -14,177 +14,160 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.34.2 -// protoc v5.27.3 +// protoc-gen-go v1.34.2 +// protoc v5.27.3 // source: configpb/config.proto package configpb import ( - keyspb "github.com/google/trillian/crypto/keyspb" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - anypb "google.golang.org/protobuf/types/known/anypb" - reflect "reflect" - sync "sync" + keyspb "github.com/google/trillian/crypto/keyspb" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // LogConfig describes the configuration options for a log instance. // // NEXT_ID: 15 type LogConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The private key used for signing Checkpoints or SCTs. - PrivateKey *anypb.Any `protobuf:"bytes,3,opt,name=private_key,json=privateKey,proto3" json:"private_key,omitempty"` - // The public key matching the above private key (if both are present). - // It can be specified for the convenience of test tools, but it not used - // by the server. - PublicKey *keyspb.PublicKey `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The public key matching the above private key (if both are present). + // It can be specified for the convenience of test tools, but it not used + // by the server. + PublicKey *keyspb.PublicKey `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` } func (x *LogConfig) Reset() { - *x = LogConfig{} - if protoimpl.UnsafeEnabled { - mi := &file_configpb_config_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + *x = LogConfig{} + if protoimpl.UnsafeEnabled { + mi := &file_configpb_config_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } func (x *LogConfig) String() string { - return protoimpl.X.MessageStringOf(x) + return protoimpl.X.MessageStringOf(x) } func (*LogConfig) ProtoMessage() {} func (x *LogConfig) ProtoReflect() protoreflect.Message { - mi := &file_configpb_config_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) + mi := &file_configpb_config_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } // Deprecated: Use LogConfig.ProtoReflect.Descriptor instead. func (*LogConfig) Descriptor() ([]byte, []int) { - return file_configpb_config_proto_rawDescGZIP(), []int{0} -} - -func (x *LogConfig) GetPrivateKey() *anypb.Any { - if x != nil { - return x.PrivateKey - } - return nil + return file_configpb_config_proto_rawDescGZIP(), []int{0} } func (x *LogConfig) GetPublicKey() *keyspb.PublicKey { - if x != nil { - return x.PublicKey - } - return nil + if x != nil { + return x.PublicKey + } + return nil } var File_configpb_config_proto protoreflect.FileDescriptor var file_configpb_config_proto_rawDesc = []byte{ - 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, - 0x62, 0x1a, 0x1a, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, - 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, - 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x74, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x35, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, - 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, - 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x0a, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x11, 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, - 0x4b, 0x65, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x4b, - 0x5a, 0x49, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x74, 0x72, - 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x6e, 0x2d, 0x74, 0x65, 0x73, 0x73, 0x65, 0x72, 0x61, 0x2f, 0x70, - 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x2f, 0x73, 0x63, 0x74, - 0x66, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, + 0x62, 0x1a, 0x1a, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, + 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3d, 0x0a, + 0x09, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x0a, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x4b, 0x5a, 0x49, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x74, 0x72, 0x69, 0x6c, + 0x6c, 0x69, 0x61, 0x6e, 0x2d, 0x74, 0x65, 0x73, 0x73, 0x65, 0x72, 0x61, 0x2f, 0x70, 0x65, 0x72, + 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x2f, 0x73, 0x63, 0x74, 0x66, 0x65, + 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( - file_configpb_config_proto_rawDescOnce sync.Once - file_configpb_config_proto_rawDescData = file_configpb_config_proto_rawDesc + file_configpb_config_proto_rawDescOnce sync.Once + file_configpb_config_proto_rawDescData = file_configpb_config_proto_rawDesc ) func file_configpb_config_proto_rawDescGZIP() []byte { - file_configpb_config_proto_rawDescOnce.Do(func() { - file_configpb_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_configpb_config_proto_rawDescData) - }) - return file_configpb_config_proto_rawDescData + file_configpb_config_proto_rawDescOnce.Do(func() { + file_configpb_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_configpb_config_proto_rawDescData) + }) + return file_configpb_config_proto_rawDescData } var file_configpb_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_configpb_config_proto_goTypes = []any{ - (*LogConfig)(nil), // 0: configpb.LogConfig - (*anypb.Any)(nil), // 1: google.protobuf.Any - (*keyspb.PublicKey)(nil), // 2: keyspb.PublicKey + (*LogConfig)(nil), // 0: configpb.LogConfig + (*keyspb.PublicKey)(nil), // 1: keyspb.PublicKey } var file_configpb_config_proto_depIdxs = []int32{ - 1, // 0: configpb.LogConfig.private_key:type_name -> google.protobuf.Any - 2, // 1: configpb.LogConfig.public_key:type_name -> keyspb.PublicKey - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 1, // 0: configpb.LogConfig.public_key:type_name -> keyspb.PublicKey + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_configpb_config_proto_init() } func file_configpb_config_proto_init() { - if File_configpb_config_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_configpb_config_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*LogConfig); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_configpb_config_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_configpb_config_proto_goTypes, - DependencyIndexes: file_configpb_config_proto_depIdxs, - MessageInfos: file_configpb_config_proto_msgTypes, - }.Build() - File_configpb_config_proto = out.File - file_configpb_config_proto_rawDesc = nil - file_configpb_config_proto_goTypes = nil - file_configpb_config_proto_depIdxs = nil + if File_configpb_config_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_configpb_config_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*LogConfig); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_configpb_config_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_configpb_config_proto_goTypes, + DependencyIndexes: file_configpb_config_proto_depIdxs, + MessageInfos: file_configpb_config_proto_msgTypes, + }.Build() + File_configpb_config_proto = out.File + file_configpb_config_proto_rawDesc = nil + file_configpb_config_proto_goTypes = nil + file_configpb_config_proto_depIdxs = nil } diff --git a/personalities/sctfe/configpb/config.proto b/personalities/sctfe/configpb/config.proto index 51cd0cc5..f650fa48 100644 --- a/personalities/sctfe/configpb/config.proto +++ b/personalities/sctfe/configpb/config.proto @@ -19,14 +19,11 @@ option go_package = "github.com/transparency-dev/trillian-tessera/personalities/ package configpb; import "crypto/keyspb/keyspb.proto"; -import "google/protobuf/any.proto"; // LogConfig describes the configuration options for a log instance. // // NEXT_ID: 15 message LogConfig { - // The private key used for signing Checkpoints or SCTs. - google.protobuf.Any private_key = 3; // The public key matching the above private key (if both are present). // It can be specified for the convenience of test tools, but it not used // by the server. diff --git a/personalities/sctfe/ct_server_gcp/main.go b/personalities/sctfe/ct_server_gcp/main.go index 819c0819..ec081bd1 100644 --- a/personalities/sctfe/ct_server_gcp/main.go +++ b/personalities/sctfe/ct_server_gcp/main.go @@ -80,6 +80,7 @@ var ( rejectUnexpired = flag.Bool("reject_unexpired", false, "If true then CTFE rejects certificates that are either currently valid or not yet valid.") extKeyUsages = flag.String("ext_key_usages", "", "If set, will restrict the set of such usages that the server will accept. By default all are accepted. The values specified must be ones known to the x509 package.") rejectExtensions = flag.String("reject_extension", "", "A list of X.509 extension OIDs, in dotted string form (e.g. '2.3.4.5') which, if present, should cause submissions to be rejected.") + privKey = flag.String("private_key", "", "Path to a private key .der file. Used to sign checkpoints and SCTs.") ) // nolint:staticcheck @@ -102,7 +103,12 @@ func main() { klog.Exitf("Failed to read config: %v", err) } - vCfg, err := sctfe.ValidateLogConfig(cfg, *origin, *projectID, *bucket, *spannerDB, *rootsPemFile, *rejectExpired, *rejectUnexpired, *extKeyUsages, *rejectExtensions, notAfterStart.t, notAfterLimit.t) + signer, err := pem.ReadPrivateKeyFile(*privKey, *privKeyPassword) + if err != nil { + klog.Exitf("Can't open key: %v", err) + } + + vCfg, err := sctfe.ValidateLogConfig(cfg, *origin, *projectID, *bucket, *spannerDB, *rootsPemFile, *rejectExpired, *rejectUnexpired, *extKeyUsages, *rejectExtensions, notAfterStart.t, notAfterLimit.t, signer) if err != nil { klog.Exitf("Invalid config: %v", err) } diff --git a/personalities/sctfe/instance.go b/personalities/sctfe/instance.go index f7a43404..4931911c 100644 --- a/personalities/sctfe/instance.go +++ b/personalities/sctfe/instance.go @@ -26,7 +26,6 @@ import ( "github.com/google/certificate-transparency-go/asn1" "github.com/google/certificate-transparency-go/x509util" - "github.com/google/trillian/crypto/keys" "github.com/google/trillian/monitoring" "golang.org/x/mod/sumdb/note" ) @@ -93,18 +92,12 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { return nil, fmt.Errorf("failed to read trusted roots: %v", err) } - var signer crypto.Signer - var err error - if signer, err = keys.NewSigner(ctx, vCfg.PrivKey); err != nil { - return nil, fmt.Errorf("failed to load private key: %v", err) - } - // TODO(phboneff): are pub keys actually used? If not, remove // If a public key has been configured for a log, check that it is consistent with the private key. if vCfg.PubKey != nil { switch pub := vCfg.PubKey.(type) { case *ecdsa.PublicKey: - if !pub.Equal(signer.Public()) { + if !pub.Equal(vCfg.Signer.Public()) { return nil, errors.New("public key is not consistent with private key") } default: @@ -120,17 +113,18 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { notAfterLimit: vCfg.NotAfterLimit, extKeyUsages: vCfg.KeyUsages, } + var err error validationOpts.rejectExtIds, err = parseOIDs(cfg.RejectExtensions) if err != nil { return nil, fmt.Errorf("failed to parse RejectExtensions: %v", err) } - logID, err := GetCTLogID(signer.Public()) + logID, err := GetCTLogID(vCfg.Signer.Public()) if err != nil { return nil, fmt.Errorf("failed to get logID for signing: %v", err) } timeSource := new(SystemTimeSource) - ctSigner := NewCpSigner(signer, vCfg.Config.Origin, logID, timeSource) + ctSigner := NewCpSigner(vCfg.Signer, vCfg.Config.Origin, logID, timeSource) if opts.CreateStorage == nil { return nil, fmt.Errorf("failed to initiate storage backend: nil createStorage") @@ -140,7 +134,7 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { return nil, fmt.Errorf("failed to initiate storage backend: %v", err) } - logInfo := newLogInfo(opts, validationOpts, signer, timeSource, storage) + logInfo := newLogInfo(opts, validationOpts, vCfg.Signer, timeSource, storage) return logInfo, nil } diff --git a/personalities/sctfe/instance_test.go b/personalities/sctfe/instance_test.go index ad439fc4..3d74995e 100644 --- a/personalities/sctfe/instance_test.go +++ b/personalities/sctfe/instance_test.go @@ -16,6 +16,7 @@ package sctfe import ( "context" + "crypto" "errors" "fmt" "net/http/httptest" @@ -30,7 +31,6 @@ import ( "github.com/google/trillian/monitoring" "github.com/transparency-dev/trillian-tessera/personalities/sctfe/configpb" "golang.org/x/mod/sumdb/note" - "google.golang.org/protobuf/types/known/anypb" ) func init() { @@ -44,9 +44,10 @@ func fakeCTStorage(_ context.Context, _ note.Signer) (*CTStorage, error) { func TestSetUpInstance(t *testing.T) { ctx := context.Background() - privKey := mustMarshalAny(&keyspb.PEMKeyFile{Path: "./testdata/ct-http-server.privkey.pem", Password: "dirk"}) - missingPrivKey := mustMarshalAny(&keyspb.PEMKeyFile{Path: "./testdata/bogus.privkey.pem", Password: "dirk"}) - wrongPassPrivKey := mustMarshalAny(&keyspb.PEMKeyFile{Path: "./testdata/ct-http-server.privkey.pem", Password: "dirkly"}) + signer, err := pem.ReadPrivateKeyFile("./testdata/ct-http-server.privkey.pem", "dirk") + if err != nil { + t.Fatalf("Can't open key: %v", err) + } var tests = []struct { desc string @@ -58,116 +59,83 @@ func TestSetUpInstance(t *testing.T) { rootsPemFile string extKeyUsages string rejectExtensions string + signer crypto.Signer ctStorage func(context.Context, note.Signer) (*CTStorage, error) wantErr string }{ { - desc: "valid", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "valid", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", rootsPemFile: "./testdata/fake-ca.cert", ctStorage: fakeCTStorage, + signer: signer, }, { - desc: "no-roots", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "no-roots", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", ctStorage: fakeCTStorage, wantErr: "specify RootsPemFile", + signer: signer, }, { - desc: "missing-root-cert", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "missing-root-cert", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", ctStorage: fakeCTStorage, rootsPemFile: "./testdata/bogus.cert", + signer: signer, wantErr: "failed to read trusted roots", }, { - desc: "missing-privkey", - cfg: &configpb.LogConfig{ - PrivateKey: missingPrivKey, - }, - origin: "log", - projectID: "project", - bucket: "bucket", - spannerDB: "spanner", - rootsPemFile: "./testdata/fake-ca.cert", - ctStorage: fakeCTStorage, - wantErr: "failed to load private key", - }, - { - desc: "privkey-wrong-password", - cfg: &configpb.LogConfig{ - PrivateKey: wrongPassPrivKey, - }, - origin: "log", - projectID: "projeot", - bucket: "bucket", - spannerDB: "spanner", - rootsPemFile: "./testdata/fake-ca.cert", - ctStorage: fakeCTStorage, - wantErr: "failed to load private key", - }, - { - desc: "valid-ekus-1", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "valid-ekus-1", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", rootsPemFile: "./testdata/fake-ca.cert", extKeyUsages: "Any", + signer: signer, ctStorage: fakeCTStorage, }, { - desc: "valid-ekus-2", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "valid-ekus-2", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", rootsPemFile: "./testdata/fake-ca.cert", extKeyUsages: "Any,ServerAuth,TimeStamping", + signer: signer, ctStorage: fakeCTStorage, }, { - desc: "valid-reject-ext", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "valid-reject-ext", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", rootsPemFile: "./testdata/fake-ca.cert", rejectExtensions: "1.2.3.4,5.6.7.8", + signer: signer, ctStorage: fakeCTStorage, }, { - desc: "invalid-reject-ext", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "invalid-reject-ext", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -175,30 +143,29 @@ func TestSetUpInstance(t *testing.T) { ctStorage: fakeCTStorage, rootsPemFile: "./testdata/fake-ca.cert", rejectExtensions: "1.2.3.4,one.banana.two.bananas", + signer: signer, wantErr: "one", }, { - desc: "missing-create-storage", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "missing-create-storage", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", rootsPemFile: "./testdata/fake-ca.cert", + signer: signer, wantErr: "failed to initiate storage backend", }, { - desc: "failing-create-storage", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "failing-create-storage", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", rootsPemFile: "./testdata/fake-ca.cert", + signer: signer, ctStorage: func(_ context.Context, _ note.Signer) (*CTStorage, error) { return nil, fmt.Errorf("I failed") }, @@ -208,7 +175,7 @@ func TestSetUpInstance(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - vCfg, err := ValidateLogConfig(test.cfg, test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, test.extKeyUsages, test.rejectExtensions, nil, nil) + vCfg, err := ValidateLogConfig(test.cfg, test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, test.extKeyUsages, test.rejectExtensions, nil, nil, signer) if err != nil { t.Fatalf("ValidateLogConfig(): %v", err) } @@ -246,10 +213,11 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { start := time.Unix(10000, 0) limit := time.Unix(12000, 0) - privKey, err := anypb.New(&keyspb.PEMKeyFile{Path: "./testdata/ct-http-server.privkey.pem", Password: "dirk"}) + signer, err := pem.ReadPrivateKeyFile("./testdata/ct-http-server.privkey.pem", "dirk") if err != nil { - t.Fatalf("Could not marshal private key proto: %v", err) + t.Fatalf(fmt.Sprintf("Can't open key: %v", err)) } + var tests = []struct { desc string cfg *configpb.LogConfig @@ -260,23 +228,21 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { rootsPemFile string notAfterStart *time.Time notAfterLimit *time.Time + signer crypto.Signer }{ { - desc: "no validation opts", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "no validation opts", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", spannerDB: "spanner", rootsPemFile: "./testdata/fake-ca.cert", + signer: signer, }, { - desc: "notAfterStart only", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "notAfterStart only", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -285,10 +251,8 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { notAfterStart: &start, }, { - desc: "notAfter range", - cfg: &configpb.LogConfig{ - PrivateKey: privKey, - }, + desc: "notAfter range", + cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -296,12 +260,13 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { rootsPemFile: "./testdata/fake-ca.cert", notAfterStart: &start, notAfterLimit: &limit, + signer: signer, }, } for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - vCfg, err := ValidateLogConfig(test.cfg, test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, "", "", test.notAfterStart, test.notAfterLimit) + vCfg, err := ValidateLogConfig(test.cfg, test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, "", "", test.notAfterStart, test.notAfterLimit, signer) if err != nil { t.Fatalf("ValidateLogConfig(): %v", err) } From 95e43fb3951fbb7e987c2f3ccefa68d81a34a7dd Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Thu, 5 Sep 2024 13:58:41 +0000 Subject: [PATCH 02/10] delete config pb and pubkey --- personalities/sctfe/config.go | 40 +---- personalities/sctfe/config_test.go | 29 +--- personalities/sctfe/configpb/config.pb.go | 173 ---------------------- personalities/sctfe/configpb/config.proto | 31 ---- personalities/sctfe/ct_server_gcp/main.go | 2 +- personalities/sctfe/instance.go | 14 -- personalities/sctfe/instance_test.go | 25 +--- 7 files changed, 5 insertions(+), 309 deletions(-) delete mode 100644 personalities/sctfe/configpb/config.pb.go delete mode 100644 personalities/sctfe/configpb/config.proto diff --git a/personalities/sctfe/config.go b/personalities/sctfe/config.go index 359cdf14..aee09232 100644 --- a/personalities/sctfe/config.go +++ b/personalities/sctfe/config.go @@ -18,15 +18,10 @@ import ( "crypto" "errors" "fmt" - "os" "strings" "time" "github.com/google/certificate-transparency-go/x509" - "github.com/google/trillian/crypto/keyspb" - "github.com/transparency-dev/trillian-tessera/personalities/sctfe/configpb" - "google.golang.org/protobuf/encoding/prototext" - "google.golang.org/protobuf/proto" "k8s.io/klog/v2" ) @@ -34,7 +29,6 @@ import ( // been successfully parsed as a result of validating it. type ValidatedLogConfig struct { Config *LogConfig - PubKey crypto.PublicKey Signer crypto.Signer // If set, ExtKeyUsages will restrict the set of such usages that the // server will accept. By default all are accepted. The values specified @@ -53,10 +47,6 @@ type LogConfig struct { // Path to the file containing root certificates that are acceptable to the // log. The certs are served through get-roots endpoint. RootsPemFile string - // The public key matching the above private key (if both are present). - // It can be specified for the convenience of test tools, but it not used - // by the server. - PublicKey *keyspb.PublicKey // If reject_expired is true then the certificate validity period will be // checked against the current time during the validation of submissions. // This will cause expired certificates to be rejected. @@ -69,25 +59,6 @@ type LogConfig struct { RejectExtensions []string } -// LogConfigFromFile creates a LogConfig options from the given -// filename, which should contain text or binary-encoded protobuf configuration -// data. -func LogConfigFromFile(filename string) (*configpb.LogConfig, error) { - cfgBytes, err := os.ReadFile(filename) - if err != nil { - return nil, err - } - - var cfg configpb.LogConfig - if txtErr := prototext.Unmarshal(cfgBytes, &cfg); txtErr != nil { - if binErr := proto.Unmarshal(cfgBytes, &cfg); binErr != nil { - return nil, fmt.Errorf("failed to parse LogConfig from %q as text protobuf (%v) or binary protobuf (%v)", filename, txtErr, binErr) - } - } - - return &cfg, nil -} - // ValidateLogConfig checks that a single log config is valid. In particular: // - A log has a private, and optionally a public key (both valid). // - Each of NotBeforeStart and NotBeforeLimit, if set, is a valid timestamp @@ -95,7 +66,7 @@ func LogConfigFromFile(filename string) (*configpb.LogConfig, error) { // - Merge delays (if present) are correct. // // Returns the validated structures (useful to avoid double validation). -func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, bucket string, spannerDB string, rootsPemFile string, rejectExpired bool, rejectUnexpired bool, extKeyUsages string, rejectExtensions string, notAfterStart *time.Time, notAfterLimit *time.Time, signer crypto.Signer) (*ValidatedLogConfig, error) { +func ValidateLogConfig(origin string, projectID string, bucket string, spannerDB string, rootsPemFile string, rejectExpired bool, rejectUnexpired bool, extKeyUsages string, rejectExtensions string, notAfterStart *time.Time, notAfterLimit *time.Time, signer crypto.Signer) (*ValidatedLogConfig, error) { if origin == "" { return nil, errors.New("empty origin") } @@ -126,7 +97,6 @@ func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, Config: &LogConfig{ Origin: origin, RootsPemFile: rootsPemFile, - PublicKey: cfg.PublicKey, RejectExpired: rejectExpired, RejectUnexpired: rejectUnexpired, RejectExtensions: lRejectExtensions, @@ -136,14 +106,6 @@ func ValidateLogConfig(cfg *configpb.LogConfig, origin string, projectID string, Signer: signer, } - // Validate the public key. - if pubKey := cfg.PublicKey; pubKey != nil { - var err error - if vCfg.PubKey, err = x509.ParsePKIXPublicKey(pubKey.Der); err != nil { - return nil, fmt.Errorf("x509.ParsePKIXPublicKey: %w", err) - } - } - if rejectExpired && rejectUnexpired { return nil, errors.New("rejecting all certificates") } diff --git a/personalities/sctfe/config_test.go b/personalities/sctfe/config_test.go index 65206d23..0fccef45 100644 --- a/personalities/sctfe/config_test.go +++ b/personalities/sctfe/config_test.go @@ -16,25 +16,13 @@ package sctfe import ( "crypto" - "fmt" "strings" "testing" "time" "github.com/google/trillian/crypto/keys/pem" - "github.com/transparency-dev/trillian-tessera/personalities/sctfe/configpb" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" ) -func mustMarshalAny(pb proto.Message) *anypb.Any { - ret, err := anypb.New(pb) - if err != nil { - panic(fmt.Sprintf("MarshalAny failed: %v", err)) - } - return ret -} - func TestValidateLogConfig(t *testing.T) { signer, err := pem.ReadPrivateKeyFile("./testdata/ct-http-server.privkey.pem", "dirk") if err != nil { @@ -46,7 +34,6 @@ func TestValidateLogConfig(t *testing.T) { for _, tc := range []struct { desc string - cfg *configpb.LogConfig origin string projectID string bucket string @@ -62,7 +49,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "empty-origin", wantErr: "empty origin", - cfg: &configpb.LogConfig{}, projectID: "project", bucket: "bucket", spannerDB: "spanner", @@ -70,7 +56,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "empty-projectID", wantErr: "empty projectID", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "", bucket: "bucket", @@ -80,7 +65,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "empty-bucket", wantErr: "empty bucket", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "", @@ -90,7 +74,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "empty-spannerDB", wantErr: "empty spannerDB", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -100,7 +83,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "rejecting-all", wantErr: "rejecting all certificates", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -112,7 +94,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "unknown-ext-key-usage-1", wantErr: "unknown extended key usage", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -123,7 +104,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "unknown-ext-key-usage-2", wantErr: "unknown extended key usage", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -134,7 +114,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "unknown-ext-key-usage-3", wantErr: "unknown extended key usage", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -145,7 +124,6 @@ func TestValidateLogConfig(t *testing.T) { { desc: "limit-before-start", wantErr: "limit before start", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -156,7 +134,6 @@ func TestValidateLogConfig(t *testing.T) { }, { desc: "ok", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -165,7 +142,6 @@ func TestValidateLogConfig(t *testing.T) { }, { desc: "ok-ext-key-usages", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -175,7 +151,6 @@ func TestValidateLogConfig(t *testing.T) { }, { desc: "ok-start-timestamp", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -185,7 +160,6 @@ func TestValidateLogConfig(t *testing.T) { }, { desc: "ok-limit-timestamp", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -195,7 +169,6 @@ func TestValidateLogConfig(t *testing.T) { }, { desc: "ok-range-timestamp", - cfg: &configpb.LogConfig{}, origin: "testlog", projectID: "project", bucket: "bucket", @@ -206,7 +179,7 @@ func TestValidateLogConfig(t *testing.T) { }, } { t.Run(tc.desc, func(t *testing.T) { - vc, err := ValidateLogConfig(tc.cfg, tc.origin, tc.projectID, tc.bucket, tc.spannerDB, "", tc.rejectExpired, tc.rejectUnexpired, tc.extKeyUsages, "", tc.notAfterStart, tc.notAfterLimit, signer) + vc, err := ValidateLogConfig(tc.origin, tc.projectID, tc.bucket, tc.spannerDB, "", tc.rejectExpired, tc.rejectUnexpired, tc.extKeyUsages, "", tc.notAfterStart, tc.notAfterLimit, signer) if len(tc.wantErr) == 0 && err != nil { t.Errorf("ValidateLogConfig()=%v, want nil", err) } diff --git a/personalities/sctfe/configpb/config.pb.go b/personalities/sctfe/configpb/config.pb.go deleted file mode 100644 index 4303de6f..00000000 --- a/personalities/sctfe/configpb/config.pb.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2017 Google LLC. 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. - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.34.2 -// protoc v5.27.3 -// source: configpb/config.proto - -package configpb - -import ( - keyspb "github.com/google/trillian/crypto/keyspb" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// LogConfig describes the configuration options for a log instance. -// -// NEXT_ID: 15 -type LogConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The public key matching the above private key (if both are present). - // It can be specified for the convenience of test tools, but it not used - // by the server. - PublicKey *keyspb.PublicKey `protobuf:"bytes,4,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"` -} - -func (x *LogConfig) Reset() { - *x = LogConfig{} - if protoimpl.UnsafeEnabled { - mi := &file_configpb_config_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *LogConfig) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*LogConfig) ProtoMessage() {} - -func (x *LogConfig) ProtoReflect() protoreflect.Message { - mi := &file_configpb_config_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use LogConfig.ProtoReflect.Descriptor instead. -func (*LogConfig) Descriptor() ([]byte, []int) { - return file_configpb_config_proto_rawDescGZIP(), []int{0} -} - -func (x *LogConfig) GetPublicKey() *keyspb.PublicKey { - if x != nil { - return x.PublicKey - } - return nil -} - -var File_configpb_config_proto protoreflect.FileDescriptor - -var file_configpb_config_proto_rawDesc = []byte{ - 0x0a, 0x15, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, - 0x62, 0x1a, 0x1a, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, - 0x2f, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3d, 0x0a, - 0x09, 0x4c, 0x6f, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x30, 0x0a, 0x0a, 0x70, 0x75, - 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x6b, 0x65, 0x79, 0x73, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x4b, 0x5a, 0x49, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2d, 0x64, 0x65, 0x76, 0x2f, 0x74, 0x72, 0x69, 0x6c, - 0x6c, 0x69, 0x61, 0x6e, 0x2d, 0x74, 0x65, 0x73, 0x73, 0x65, 0x72, 0x61, 0x2f, 0x70, 0x65, 0x72, - 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x2f, 0x73, 0x63, 0x74, 0x66, 0x65, - 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} - -var ( - file_configpb_config_proto_rawDescOnce sync.Once - file_configpb_config_proto_rawDescData = file_configpb_config_proto_rawDesc -) - -func file_configpb_config_proto_rawDescGZIP() []byte { - file_configpb_config_proto_rawDescOnce.Do(func() { - file_configpb_config_proto_rawDescData = protoimpl.X.CompressGZIP(file_configpb_config_proto_rawDescData) - }) - return file_configpb_config_proto_rawDescData -} - -var file_configpb_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_configpb_config_proto_goTypes = []any{ - (*LogConfig)(nil), // 0: configpb.LogConfig - (*keyspb.PublicKey)(nil), // 1: keyspb.PublicKey -} -var file_configpb_config_proto_depIdxs = []int32{ - 1, // 0: configpb.LogConfig.public_key:type_name -> keyspb.PublicKey - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_configpb_config_proto_init() } -func file_configpb_config_proto_init() { - if File_configpb_config_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_configpb_config_proto_msgTypes[0].Exporter = func(v any, i int) any { - switch v := v.(*LogConfig); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_configpb_config_proto_rawDesc, - NumEnums: 0, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_configpb_config_proto_goTypes, - DependencyIndexes: file_configpb_config_proto_depIdxs, - MessageInfos: file_configpb_config_proto_msgTypes, - }.Build() - File_configpb_config_proto = out.File - file_configpb_config_proto_rawDesc = nil - file_configpb_config_proto_goTypes = nil - file_configpb_config_proto_depIdxs = nil -} diff --git a/personalities/sctfe/configpb/config.proto b/personalities/sctfe/configpb/config.proto deleted file mode 100644 index f650fa48..00000000 --- a/personalities/sctfe/configpb/config.proto +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2017 Google LLC. 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. - -syntax = "proto3"; - -option go_package = "github.com/transparency-dev/trillian-tessera/personalities/sctfe/configpb"; - -package configpb; - -import "crypto/keyspb/keyspb.proto"; - -// LogConfig describes the configuration options for a log instance. -// -// NEXT_ID: 15 -message LogConfig { - // The public key matching the above private key (if both are present). - // It can be specified for the convenience of test tools, but it not used - // by the server. - keyspb.PublicKey public_key = 4; -} diff --git a/personalities/sctfe/ct_server_gcp/main.go b/personalities/sctfe/ct_server_gcp/main.go index ec081bd1..58489712 100644 --- a/personalities/sctfe/ct_server_gcp/main.go +++ b/personalities/sctfe/ct_server_gcp/main.go @@ -108,7 +108,7 @@ func main() { klog.Exitf("Can't open key: %v", err) } - vCfg, err := sctfe.ValidateLogConfig(cfg, *origin, *projectID, *bucket, *spannerDB, *rootsPemFile, *rejectExpired, *rejectUnexpired, *extKeyUsages, *rejectExtensions, notAfterStart.t, notAfterLimit.t, signer) + vCfg, err := sctfe.ValidateLogConfig(*origin, *projectID, *bucket, *spannerDB, *rootsPemFile, *rejectExpired, *rejectUnexpired, *extKeyUsages, *rejectExtensions, notAfterStart.t, notAfterLimit.t, signer) if err != nil { klog.Exitf("Invalid config: %v", err) } diff --git a/personalities/sctfe/instance.go b/personalities/sctfe/instance.go index 4931911c..044aa079 100644 --- a/personalities/sctfe/instance.go +++ b/personalities/sctfe/instance.go @@ -17,7 +17,6 @@ package sctfe import ( "context" "crypto" - "crypto/ecdsa" "errors" "fmt" "strconv" @@ -92,19 +91,6 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { return nil, fmt.Errorf("failed to read trusted roots: %v", err) } - // TODO(phboneff): are pub keys actually used? If not, remove - // If a public key has been configured for a log, check that it is consistent with the private key. - if vCfg.PubKey != nil { - switch pub := vCfg.PubKey.(type) { - case *ecdsa.PublicKey: - if !pub.Equal(vCfg.Signer.Public()) { - return nil, errors.New("public key is not consistent with private key") - } - default: - return nil, errors.New("failed to verify consistency of public key with private key") - } - } - validationOpts := CertValidationOpts{ trustedRoots: roots, rejectExpired: cfg.RejectExpired, diff --git a/personalities/sctfe/instance_test.go b/personalities/sctfe/instance_test.go index 3d74995e..a014f9d1 100644 --- a/personalities/sctfe/instance_test.go +++ b/personalities/sctfe/instance_test.go @@ -25,18 +25,11 @@ import ( "time" ct "github.com/google/certificate-transparency-go" - "github.com/google/trillian/crypto/keys" "github.com/google/trillian/crypto/keys/pem" - "github.com/google/trillian/crypto/keyspb" "github.com/google/trillian/monitoring" - "github.com/transparency-dev/trillian-tessera/personalities/sctfe/configpb" "golang.org/x/mod/sumdb/note" ) -func init() { - keys.RegisterHandler(&keyspb.PEMKeyFile{}, pem.FromProto) -} - func fakeCTStorage(_ context.Context, _ note.Signer) (*CTStorage, error) { return &CTStorage{}, nil } @@ -51,7 +44,6 @@ func TestSetUpInstance(t *testing.T) { var tests = []struct { desc string - cfg *configpb.LogConfig origin string projectID string bucket string @@ -65,7 +57,6 @@ func TestSetUpInstance(t *testing.T) { }{ { desc: "valid", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -76,7 +67,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "no-roots", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -87,7 +77,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "missing-root-cert", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -99,7 +88,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "valid-ekus-1", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -111,7 +99,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "valid-ekus-2", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -123,7 +110,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "valid-reject-ext", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -135,7 +121,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "invalid-reject-ext", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -148,7 +133,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "missing-create-storage", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -159,7 +143,6 @@ func TestSetUpInstance(t *testing.T) { }, { desc: "failing-create-storage", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -175,7 +158,7 @@ func TestSetUpInstance(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - vCfg, err := ValidateLogConfig(test.cfg, test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, test.extKeyUsages, test.rejectExtensions, nil, nil, signer) + vCfg, err := ValidateLogConfig(test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, test.extKeyUsages, test.rejectExtensions, nil, nil, signer) if err != nil { t.Fatalf("ValidateLogConfig(): %v", err) } @@ -220,7 +203,6 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { var tests = []struct { desc string - cfg *configpb.LogConfig origin string projectID string bucket string @@ -232,7 +214,6 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { }{ { desc: "no validation opts", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -242,7 +223,6 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { }, { desc: "notAfterStart only", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -252,7 +232,6 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { }, { desc: "notAfter range", - cfg: &configpb.LogConfig{}, origin: "log", projectID: "project", bucket: "bucket", @@ -266,7 +245,7 @@ func TestSetUpInstanceSetsValidationOpts(t *testing.T) { for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - vCfg, err := ValidateLogConfig(test.cfg, test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, "", "", test.notAfterStart, test.notAfterLimit, signer) + vCfg, err := ValidateLogConfig(test.origin, test.projectID, test.bucket, test.spannerDB, test.rootsPemFile, false, false, "", "", test.notAfterStart, test.notAfterLimit, signer) if err != nil { t.Fatalf("ValidateLogConfig(): %v", err) } From be81c48347ef700323d85d092fdead8e9f236a1b Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Thu, 5 Sep 2024 14:20:01 +0000 Subject: [PATCH 03/10] remove key handlers --- personalities/sctfe/ct_server_gcp/main.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/personalities/sctfe/ct_server_gcp/main.go b/personalities/sctfe/ct_server_gcp/main.go index 58489712..962ffc1a 100644 --- a/personalities/sctfe/ct_server_gcp/main.go +++ b/personalities/sctfe/ct_server_gcp/main.go @@ -29,6 +29,7 @@ import ( "syscall" "time" + "github.com/emicklei/proto" "github.com/google/trillian/crypto/keys" "github.com/google/trillian/crypto/keys/der" "github.com/google/trillian/crypto/keys/pem" @@ -45,7 +46,6 @@ import ( gcpSCTFE "github.com/transparency-dev/trillian-tessera/personalities/sctfe/storage/gcp" gcpTessera "github.com/transparency-dev/trillian-tessera/storage/gcp" "golang.org/x/mod/sumdb/note" - "google.golang.org/protobuf/proto" "k8s.io/klog/v2" ) @@ -98,11 +98,6 @@ func main() { return nil, fmt.Errorf("pkcs11: got %T, want *keyspb.PKCS11Config", pb) }) - cfg, err := sctfe.LogConfigFromFile(*logConfig) - if err != nil { - klog.Exitf("Failed to read config: %v", err) - } - signer, err := pem.ReadPrivateKeyFile(*privKey, *privKeyPassword) if err != nil { klog.Exitf("Can't open key: %v", err) From 93c8a60ee99d6ebf980211dae02233fbf51e1b53 Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Thu, 5 Sep 2024 14:49:54 +0000 Subject: [PATCH 04/10] switch to pem files --- personalities/sctfe/ct_server_gcp/main.go | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/personalities/sctfe/ct_server_gcp/main.go b/personalities/sctfe/ct_server_gcp/main.go index 962ffc1a..4d3ed1b5 100644 --- a/personalities/sctfe/ct_server_gcp/main.go +++ b/personalities/sctfe/ct_server_gcp/main.go @@ -17,7 +17,6 @@ package main import ( "context" - "crypto" "crypto/tls" "flag" "fmt" @@ -29,12 +28,7 @@ import ( "syscall" "time" - "github.com/emicklei/proto" - "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/keys/pkcs11" - "github.com/google/trillian/crypto/keyspb" "github.com/google/trillian/monitoring/opencensus" "github.com/google/trillian/monitoring/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -81,6 +75,7 @@ var ( extKeyUsages = flag.String("ext_key_usages", "", "If set, will restrict the set of such usages that the server will accept. By default all are accepted. The values specified must be ones known to the x509 package.") rejectExtensions = flag.String("reject_extension", "", "A list of X.509 extension OIDs, in dotted string form (e.g. '2.3.4.5') which, if present, should cause submissions to be rejected.") privKey = flag.String("private_key", "", "Path to a private key .der file. Used to sign checkpoints and SCTs.") + privKeyPass = flag.String("password", "", "private_key password.") ) // nolint:staticcheck @@ -89,16 +84,7 @@ func main() { flag.Parse() ctx := context.Background() - keys.RegisterHandler(&keyspb.PEMKeyFile{}, pem.FromProto) - keys.RegisterHandler(&keyspb.PrivateKey{}, der.FromProto) - keys.RegisterHandler(&keyspb.PKCS11Config{}, func(ctx context.Context, pb proto.Message) (crypto.Signer, error) { - if cfg, ok := pb.(*keyspb.PKCS11Config); ok { - return pkcs11.FromConfig(*pkcs11ModulePath, cfg) - } - return nil, fmt.Errorf("pkcs11: got %T, want *keyspb.PKCS11Config", pb) - }) - - signer, err := pem.ReadPrivateKeyFile(*privKey, *privKeyPassword) + signer, err := pem.ReadPrivateKeyFile(*privKey, *privKeyPass) if err != nil { klog.Exitf("Can't open key: %v", err) } From 45d825bc29ce21e8eea1e3a0fce696812e991732 Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Fri, 6 Sep 2024 07:34:00 +0000 Subject: [PATCH 05/10] edit comments --- personalities/sctfe/config.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/personalities/sctfe/config.go b/personalities/sctfe/config.go index aee09232..9891c432 100644 --- a/personalities/sctfe/config.go +++ b/personalities/sctfe/config.go @@ -29,29 +29,36 @@ import ( // been successfully parsed as a result of validating it. type ValidatedLogConfig struct { Config *LogConfig + // Used to sign the checkpoint and SCTs. + // TODO(phboneff): check that this is RSA or ECDSA only. Signer crypto.Signer // If set, ExtKeyUsages will restrict the set of such usages that the // server will accept. By default all are accepted. The values specified // must be ones known to the x509 package. - KeyUsages []x509.ExtKeyUsage + KeyUsages []x509.ExtKeyUsage + // NotAfterStart defines the start of the range of acceptable NotAfter + // values, inclusive. + // Leaving this unset implies no lower bound to the range. NotAfterStart *time.Time + // NotAfterLimit defines the end of the range of acceptable NotAfter values, + // exclusive. + // Leaving this unset implies no upper bound to the range. NotAfterLimit *time.Time } // TODO(phboneff): inline this in ValidatedLogConfig and probably inline things further -// TODO(phboneff): edit comments type LogConfig struct { - // origin identifies the log. It will be used in its checkpoint, and - // is also its submission prefix, as per https://c2sp.org/static-ct-api + // Origin identifies the log. It will be used in its checkpoint, and + // is also its submission prefix, as per https://c2sp.org/static-ct-api. Origin string // Path to the file containing root certificates that are acceptable to the // log. The certs are served through get-roots endpoint. RootsPemFile string - // If reject_expired is true then the certificate validity period will be + // If RejectExpired is true then the certificate validity period will be // checked against the current time during the validation of submissions. // This will cause expired certificates to be rejected. RejectExpired bool - // If reject_unexpired is true then CTFE rejects certificates that are either + // If RejectUnexpired is true then CTFE rejects certificates that are either // currently valid or not yet valid. RejectUnexpired bool // A list of X.509 extension OIDs, in dotted string form (e.g. "2.3.4.5") From e24f0da715808dca5d98ae28c986c03abe5f3cd4 Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Fri, 6 Sep 2024 08:33:32 +0000 Subject: [PATCH 06/10] inline logconfig --- personalities/sctfe/config.go | 29 +++++++++++----------------- personalities/sctfe/handlers.go | 3 +-- personalities/sctfe/handlers_test.go | 5 ++--- personalities/sctfe/instance.go | 17 ++++++++-------- 4 files changed, 22 insertions(+), 32 deletions(-) diff --git a/personalities/sctfe/config.go b/personalities/sctfe/config.go index 9891c432..69b92725 100644 --- a/personalities/sctfe/config.go +++ b/personalities/sctfe/config.go @@ -28,7 +28,9 @@ import ( // ValidatedLogConfig represents the LogConfig with the information that has // been successfully parsed as a result of validating it. type ValidatedLogConfig struct { - Config *LogConfig + // Origin identifies the log. It will be used in its checkpoint, and + // is also its submission prefix, as per https://c2sp.org/static-ct-api. + Origin string // Used to sign the checkpoint and SCTs. // TODO(phboneff): check that this is RSA or ECDSA only. Signer crypto.Signer @@ -44,13 +46,6 @@ type ValidatedLogConfig struct { // exclusive. // Leaving this unset implies no upper bound to the range. NotAfterLimit *time.Time -} - -// TODO(phboneff): inline this in ValidatedLogConfig and probably inline things further -type LogConfig struct { - // Origin identifies the log. It will be used in its checkpoint, and - // is also its submission prefix, as per https://c2sp.org/static-ct-api. - Origin string // Path to the file containing root certificates that are acceptable to the // log. The certs are served through get-roots endpoint. RootsPemFile string @@ -101,16 +96,14 @@ func ValidateLogConfig(origin string, projectID string, bucket string, spannerDB } vCfg := ValidatedLogConfig{ - Config: &LogConfig{ - Origin: origin, - RootsPemFile: rootsPemFile, - RejectExpired: rejectExpired, - RejectUnexpired: rejectUnexpired, - RejectExtensions: lRejectExtensions, - }, - NotAfterStart: notAfterStart, - NotAfterLimit: notAfterLimit, - Signer: signer, + Origin: origin, + RootsPemFile: rootsPemFile, + RejectExpired: rejectExpired, + RejectUnexpired: rejectUnexpired, + RejectExtensions: lRejectExtensions, + NotAfterStart: notAfterStart, + NotAfterLimit: notAfterLimit, + Signer: signer, } if rejectExpired && rejectUnexpired { diff --git a/personalities/sctfe/handlers.go b/personalities/sctfe/handlers.go index 648aad2f..f776c17b 100644 --- a/personalities/sctfe/handlers.go +++ b/personalities/sctfe/handlers.go @@ -216,8 +216,7 @@ func newLogInfo( timeSource TimeSource, storage Storage, ) *logInfo { - vCfg := instanceOpts.Validated - cfg := vCfg.Config + cfg := instanceOpts.Validated li := &logInfo{ LogOrigin: cfg.Origin, diff --git a/personalities/sctfe/handlers_test.go b/personalities/sctfe/handlers_test.go index c1d92d0a..3bb0873c 100644 --- a/personalities/sctfe/handlers_test.go +++ b/personalities/sctfe/handlers_test.go @@ -75,9 +75,8 @@ func setupTest(t *testing.T, pemRoots []string, signer crypto.Signer) handlerTes rejectExpired: false, } - cfg := &LogConfig{Origin: "example.com"} - vCfg := &ValidatedLogConfig{Config: cfg} - iOpts := InstanceOptions{Validated: vCfg, Deadline: time.Millisecond * 500, MetricFactory: monitoring.InertMetricFactory{}, RequestLog: new(DefaultRequestLog)} + cfg := &ValidatedLogConfig{Origin: "example.com"} + iOpts := InstanceOptions{Validated: cfg, Deadline: time.Millisecond * 500, MetricFactory: monitoring.InertMetricFactory{}, RequestLog: new(DefaultRequestLog)} info.li = newLogInfo(iOpts, vOpts, signer, fakeTimeSource, info.storage) for _, pemRoot := range pemRoots { diff --git a/personalities/sctfe/instance.go b/personalities/sctfe/instance.go index 044aa079..d4824e80 100644 --- a/personalities/sctfe/instance.go +++ b/personalities/sctfe/instance.go @@ -71,13 +71,12 @@ func SetUpInstance(ctx context.Context, opts InstanceOptions) (*Instance, error) if err != nil { return nil, err } - handlers := logInfo.Handlers(opts.Validated.Config.Origin) + handlers := logInfo.Handlers(opts.Validated.Origin) return &Instance{Handlers: handlers, li: logInfo}, nil } func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { - vCfg := opts.Validated - cfg := vCfg.Config + cfg := opts.Validated // TODO(phboneff): move to ValidateLogConfig // Check config validity. @@ -95,9 +94,9 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { trustedRoots: roots, rejectExpired: cfg.RejectExpired, rejectUnexpired: cfg.RejectUnexpired, - notAfterStart: vCfg.NotAfterStart, - notAfterLimit: vCfg.NotAfterLimit, - extKeyUsages: vCfg.KeyUsages, + notAfterStart: cfg.NotAfterStart, + notAfterLimit: cfg.NotAfterLimit, + extKeyUsages: cfg.KeyUsages, } var err error validationOpts.rejectExtIds, err = parseOIDs(cfg.RejectExtensions) @@ -105,12 +104,12 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { return nil, fmt.Errorf("failed to parse RejectExtensions: %v", err) } - logID, err := GetCTLogID(vCfg.Signer.Public()) + logID, err := GetCTLogID(cfg.Signer.Public()) if err != nil { return nil, fmt.Errorf("failed to get logID for signing: %v", err) } timeSource := new(SystemTimeSource) - ctSigner := NewCpSigner(vCfg.Signer, vCfg.Config.Origin, logID, timeSource) + ctSigner := NewCpSigner(cfg.Signer, cfg.Origin, logID, timeSource) if opts.CreateStorage == nil { return nil, fmt.Errorf("failed to initiate storage backend: nil createStorage") @@ -120,7 +119,7 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { return nil, fmt.Errorf("failed to initiate storage backend: %v", err) } - logInfo := newLogInfo(opts, validationOpts, vCfg.Signer, timeSource, storage) + logInfo := newLogInfo(opts, validationOpts, cfg.Signer, timeSource, storage) return logInfo, nil } From 50c6b0470c6a60704f2228935559579e558d70ca Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Fri, 6 Sep 2024 07:57:06 +0000 Subject: [PATCH 07/10] inline setUpLogInfo --- personalities/sctfe/instance.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/personalities/sctfe/instance.go b/personalities/sctfe/instance.go index d4824e80..97059a90 100644 --- a/personalities/sctfe/instance.go +++ b/personalities/sctfe/instance.go @@ -67,15 +67,6 @@ func (i *Instance) GetPublicKey() crypto.PublicKey { // configuration, and returns an object containing a set of handlers for this // log, and an STH getter. func SetUpInstance(ctx context.Context, opts InstanceOptions) (*Instance, error) { - logInfo, err := setUpLogInfo(ctx, opts) - if err != nil { - return nil, err - } - handlers := logInfo.Handlers(opts.Validated.Origin) - return &Instance{Handlers: handlers, li: logInfo}, nil -} - -func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { cfg := opts.Validated // TODO(phboneff): move to ValidateLogConfig @@ -120,7 +111,9 @@ func setUpLogInfo(ctx context.Context, opts InstanceOptions) (*logInfo, error) { } logInfo := newLogInfo(opts, validationOpts, cfg.Signer, timeSource, storage) - return logInfo, nil + + handlers := logInfo.Handlers(opts.Validated.Origin) + return &Instance{Handlers: handlers, li: logInfo}, nil } func parseOIDs(oids []string) ([]asn1.ObjectIdentifier, error) { From a2edfefd0950742a8156520d54d09d604aa9f3e0 Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Fri, 6 Sep 2024 08:05:27 +0000 Subject: [PATCH 08/10] move the check for rootspemfiles --- personalities/sctfe/config.go | 4 ++++ personalities/sctfe/config_test.go | 34 ++++++++++++++++++++++------ personalities/sctfe/instance.go | 7 ------ personalities/sctfe/instance_test.go | 17 +++++++------- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/personalities/sctfe/config.go b/personalities/sctfe/config.go index 69b92725..8e524c5b 100644 --- a/personalities/sctfe/config.go +++ b/personalities/sctfe/config.go @@ -86,6 +86,10 @@ func ValidateLogConfig(origin string, projectID string, bucket string, spannerDB return nil, errors.New("empty spannerDB") } + if rootsPemFile == "" { + return nil, errors.New("empty rootsPemFile") + } + lExtKeyUsages := []string{} lRejectExtensions := []string{} if extKeyUsages != "" { diff --git a/personalities/sctfe/config_test.go b/personalities/sctfe/config_test.go index 0fccef45..042e1547 100644 --- a/personalities/sctfe/config_test.go +++ b/personalities/sctfe/config_test.go @@ -39,6 +39,7 @@ func TestValidateLogConfig(t *testing.T) { bucket string spannerDB string wantErr string + rootsPemFile string rejectExpired bool rejectUnexpired bool extKeyUsages string @@ -80,6 +81,15 @@ func TestValidateLogConfig(t *testing.T) { spannerDB: "", signer: signer, }, + { + desc: "empty-rootsPemFile", + wantErr: "empty rootsPemFile", + origin: "testlog", + projectID: "project", + bucket: "bucket", + spannerDB: "spanner", + signer: signer, + }, { desc: "rejecting-all", wantErr: "rejecting all certificates", @@ -87,6 +97,7 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", rejectExpired: true, rejectUnexpired: true, signer: signer, @@ -98,6 +109,7 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", extKeyUsages: "wrong_usage", signer: signer, }, @@ -108,6 +120,7 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", extKeyUsages: "ClientAuth,ServerAuth,TimeStomping", signer: signer, }, @@ -118,6 +131,7 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", extKeyUsages: "Any ", signer: signer, }, @@ -128,17 +142,19 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", notAfterStart: &t200, notAfterLimit: &t100, signer: signer, }, { - desc: "ok", - origin: "testlog", - projectID: "project", - bucket: "bucket", - spannerDB: "spanner", - signer: signer, + desc: "ok", + origin: "testlog", + projectID: "project", + bucket: "bucket", + spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", + signer: signer, }, { desc: "ok-ext-key-usages", @@ -146,6 +162,7 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", extKeyUsages: "ServerAuth,ClientAuth,OCSPSigning", signer: signer, }, @@ -155,6 +172,7 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", notAfterStart: &t100, signer: signer, }, @@ -164,6 +182,7 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", notAfterStart: &t200, signer: signer, }, @@ -173,13 +192,14 @@ func TestValidateLogConfig(t *testing.T) { projectID: "project", bucket: "bucket", spannerDB: "spanner", + rootsPemFile: "./testdata/fake-ca.cert", notAfterStart: &t100, notAfterLimit: &t200, signer: signer, }, } { t.Run(tc.desc, func(t *testing.T) { - vc, err := ValidateLogConfig(tc.origin, tc.projectID, tc.bucket, tc.spannerDB, "", tc.rejectExpired, tc.rejectUnexpired, tc.extKeyUsages, "", tc.notAfterStart, tc.notAfterLimit, signer) + vc, err := ValidateLogConfig(tc.origin, tc.projectID, tc.bucket, tc.spannerDB, tc.rootsPemFile, tc.rejectExpired, tc.rejectUnexpired, tc.extKeyUsages, "", tc.notAfterStart, tc.notAfterLimit, signer) if len(tc.wantErr) == 0 && err != nil { t.Errorf("ValidateLogConfig()=%v, want nil", err) } diff --git a/personalities/sctfe/instance.go b/personalities/sctfe/instance.go index 97059a90..1a7d89d5 100644 --- a/personalities/sctfe/instance.go +++ b/personalities/sctfe/instance.go @@ -17,7 +17,6 @@ package sctfe import ( "context" "crypto" - "errors" "fmt" "strconv" "strings" @@ -69,12 +68,6 @@ func (i *Instance) GetPublicKey() crypto.PublicKey { func SetUpInstance(ctx context.Context, opts InstanceOptions) (*Instance, error) { cfg := opts.Validated - // TODO(phboneff): move to ValidateLogConfig - // Check config validity. - if len(cfg.RootsPemFile) == 0 { - return nil, errors.New("need to specify RootsPemFile") - } - // Load the trusted roots. roots := x509util.NewPEMCertPool() if err := roots.AppendCertsFromPEMFile(cfg.RootsPemFile); err != nil { diff --git a/personalities/sctfe/instance_test.go b/personalities/sctfe/instance_test.go index a014f9d1..ae35c392 100644 --- a/personalities/sctfe/instance_test.go +++ b/personalities/sctfe/instance_test.go @@ -66,14 +66,15 @@ func TestSetUpInstance(t *testing.T) { signer: signer, }, { - desc: "no-roots", - origin: "log", - projectID: "project", - bucket: "bucket", - spannerDB: "spanner", - ctStorage: fakeCTStorage, - wantErr: "specify RootsPemFile", - signer: signer, + desc: "no-roots", + origin: "log", + projectID: "project", + bucket: "bucket", + spannerDB: "spanner", + rootsPemFile: "./testdata/nofile", + ctStorage: fakeCTStorage, + wantErr: "failed to read trusted roots", + signer: signer, }, { desc: "missing-root-cert", From fe6d766474cb97aafdaa2fe4773cc67df59c1a02 Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Mon, 9 Sep 2024 13:21:09 +0000 Subject: [PATCH 09/10] add kms comment --- personalities/sctfe/ct_server_gcp/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/personalities/sctfe/ct_server_gcp/main.go b/personalities/sctfe/ct_server_gcp/main.go index 4d3ed1b5..d7abced9 100644 --- a/personalities/sctfe/ct_server_gcp/main.go +++ b/personalities/sctfe/ct_server_gcp/main.go @@ -84,6 +84,7 @@ func main() { flag.Parse() ctx := context.Background() + // TODO(phboneff): move to something else, like KMS signer, err := pem.ReadPrivateKeyFile(*privKey, *privKeyPass) if err != nil { klog.Exitf("Can't open key: %v", err) From 5c31604e8d3a227d20cfa79ea60bcdb986b8a255 Mon Sep 17 00:00:00 2001 From: Philippe Boneff Date: Mon, 9 Sep 2024 13:31:51 +0000 Subject: [PATCH 10/10] Delete old flags --- personalities/sctfe/ct_server_gcp/main.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/personalities/sctfe/ct_server_gcp/main.go b/personalities/sctfe/ct_server_gcp/main.go index d7abced9..9265716e 100644 --- a/personalities/sctfe/ct_server_gcp/main.go +++ b/personalities/sctfe/ct_server_gcp/main.go @@ -53,17 +53,16 @@ var ( notAfterStart timestampFlag notAfterLimit timestampFlag - httpEndpoint = flag.String("http_endpoint", "localhost:6962", "Endpoint for HTTP (host:port).") - tlsCert = flag.String("tls_certificate", "", "Path to server TLS certificate.") - tlsKey = flag.String("tls_key", "", "Path to server TLS private key.") - metricsEndpoint = flag.String("metrics_endpoint", "", "Endpoint for serving metrics; if left empty, metrics will be visible on --http_endpoint.") + httpEndpoint = flag.String("http_endpoint", "localhost:6962", "Endpoint for HTTP (host:port).") + tlsCert = flag.String("tls_certificate", "", "Path to server TLS certificate.") + tlsKey = flag.String("tls_key", "", "Path to server TLS private key.") + metricsEndpoint = flag.String("metrics_endpoint", "", "Endpoint for serving metrics; if left empty, metrics will be visible on --http_endpoint.") + // TODO(phboneff): delete / rename rpcDeadline = flag.Duration("rpc_deadline", time.Second*10, "Deadline for backend RPC requests.") - logConfig = flag.String("log_config", "", "File holding log config in text proto format.") maskInternalErrors = flag.Bool("mask_internal_errors", false, "Don't return error strings with Internal Server Error HTTP responses.") tracing = flag.Bool("tracing", false, "If true opencensus Stackdriver tracing will be enabled. See https://opencensus.io/.") tracingProjectID = flag.String("tracing_project_id", "", "project ID to pass to stackdriver. Can be empty for GCP, consult docs for other platforms.") tracingPercent = flag.Int("tracing_percent", 0, "Percent of requests to be traced. Zero is a special case to use the DefaultSampler.") - pkcs11ModulePath = flag.String("pkcs11_module_path", "", "Path to the PKCS#11 module to use for keys that use the PKCS#11 interface.") dedupPath = flag.String("dedup_path", "", "Path to the deduplication database.") origin = flag.String("origin", "", "Origin of the log, for checkpoints and the monitoring prefix.") projectID = flag.String("project_id", "", "GCP ProjectID.")