diff --git a/cmd/rekor-server/app/root.go b/cmd/rekor-server/app/root.go index 13bc56c03..0d10b2f38 100644 --- a/cmd/rekor-server/app/root.go +++ b/cmd/rekor-server/app/root.go @@ -73,7 +73,11 @@ func init() { } rootCmd.PersistentFlags().String("rekor_server.hostname", hostname, "public hostname of instance") rootCmd.PersistentFlags().String("rekor_server.address", "127.0.0.1", "Address to bind to") - rootCmd.PersistentFlags().String("rekor_server.signer", "memory", "Rekor signer to use. Current valid options include: [gcpkms, memory]") + + rootCmd.PersistentFlags().String("rekor_server.signer", "memory", + `Rekor signer to use. Valid options are: [gcpkms, memory, filename containing PEM encoded private key]. + Memory and file-based signers should only be used for testing.`) + rootCmd.PersistentFlags().String("rekor_server.signer-passwd", "", "Password to decrypt signer private key") rootCmd.PersistentFlags().Uint16("port", 3000, "Port to bind to") diff --git a/go.mod b/go.mod index c57e4ca8e..02349294d 100644 --- a/go.mod +++ b/go.mod @@ -56,6 +56,8 @@ require ( require golang.org/x/exp v0.0.0-20220823124025-807a23277127 +require filippo.io/edwards25519 v1.0.0-rc.1 // indirect + require ( cloud.google.com/go v0.103.0 // indirect cloud.google.com/go/compute v1.7.0 // indirect @@ -116,12 +118,13 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.mongodb.org/mongo-driver v1.10.0 // indirect go.opencensus.io v0.23.0 // indirect + go.step.sm/crypto v0.19.0 go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 // indirect golang.org/x/sys v0.0.0-20220907062415-87db552b00fd // indirect golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect google.golang.org/api v0.95.0 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 9f4cea409..2746cf302 100644 --- a/go.sum +++ b/go.sum @@ -80,6 +80,8 @@ contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod contrib.go.opencensus.io/exporter/stackdriver v0.13.10/go.mod h1:I5htMbyta491eUxufwwZPQdcKvvgzMB4O9ni41YnIM8= contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/Azure/azure-amqp-common-go/v3 v3.2.1/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= github.com/Azure/azure-amqp-common-go/v3 v3.2.2/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= @@ -715,6 +717,7 @@ github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -822,6 +825,8 @@ go.opentelemetry.io/contrib/propagators v0.19.0 h1:HrixVNZYFjUl/Db+Tr3DhqzLsVW9G go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g= go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.step.sm/crypto v0.19.0 h1:WxjUDeTDpuPZ1IR3v6c4jc6WdlQlS5IYYQBhfnG5uW0= +go.step.sm/crypto v0.19.0/go.mod h1:qZ+pNU1nV+THwP7TPTNCRMRr9xrRURhETTAK7U5psfw= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= @@ -1107,8 +1112,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/api/api.go b/pkg/api/api.go index efbece057..1aa031bdd 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -90,7 +90,8 @@ func NewAPI(treeID uint) (*API, error) { log.Logger.Infof("Starting Rekor server with active tree %v", tid) ranges.SetActive(tid) - rekorSigner, err := signer.New(ctx, viper.GetString("rekor_server.signer")) + rekorSigner, err := signer.New(ctx, viper.GetString("rekor_server.signer"), + viper.GetString("rekor_server.signer-passwd")) if err != nil { return nil, fmt.Errorf("getting new signer: %w", err) } diff --git a/pkg/signer/file.go b/pkg/signer/file.go new file mode 100644 index 000000000..450ca121b --- /dev/null +++ b/pkg/signer/file.go @@ -0,0 +1,43 @@ +/* +Copyright The Rekor Authors. + +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 signer + +import ( + "crypto" + "fmt" + + "github.com/sigstore/sigstore/pkg/signature" + "go.step.sm/crypto/pemutil" +) + +// returns an file based signer and verify, used for spinning up local instances +type File struct { + signature.SignerVerifier +} + +func NewFile(keyPath, keyPass string) (*File, error) { + opaqueKey, err := pemutil.Read(keyPath, pemutil.WithPassword([]byte(keyPass))) + if err != nil { + return nil, fmt.Errorf("file: provide a valid signer, %s is not valid: %w", keyPath, err) + } + + signer, err := signature.LoadSignerVerifier(opaqueKey, crypto.SHA256) + if err != nil { + return nil, fmt.Errorf(`file: loaded private key from %s can't be used to sign: %w`, keyPath, err) + } + return &File{signer}, nil +} diff --git a/pkg/signer/file_test.go b/pkg/signer/file_test.go new file mode 100644 index 000000000..fc2d06aca --- /dev/null +++ b/pkg/signer/file_test.go @@ -0,0 +1,72 @@ +/* +Copyright The Rekor Authors. + +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 signer + +import ( + "os" + "path/filepath" + "testing" +) + +const testEcdsaKey = ` +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,1ee56fe067d83265fe430391edfa6586 + +W5NqqRe5rOVe4OvxehYKm6wscR1JFoyRyd8M+Rutp8Q2lxPuKFhR4FZ61b0yy6pr +LGJGQWOTIZxrNZ8g4JeS9I3huDWGloZRI2fbTg69HK4EiQQWUc1wS1TWAVoaf4fr +LclBWxp2UzqHDaNJ0/2DoGFZhaeMU84VA1O41lO+p5Cx4bms0yWeEHwOrf2AmnNY +l5Zm9zoPpXxaDEPSTs5c1loRmmxPHKgb68oZPxEnsCg= +-----END EC PRIVATE KEY-----` + +func TestFile(t *testing.T) { + testKeyPass := `password123` + td := t.TempDir() + keyFile := filepath.Join(td, "ecdsa-key.pem") + if err := os.WriteFile(keyFile, []byte(testEcdsaKey), 0644); err != nil { + t.Fatal(err) + } + + tests := []struct { + name string + keyPath string + keyPass string + wantErr bool + }{ + { + name: "valid ecdsa", + keyPath: keyFile, + keyPass: testKeyPass, + wantErr: false, + }, + { + name: "invalid pass", + keyPath: keyFile, + keyPass: "123", + wantErr: true, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + tc := tc + _, err := NewFile(tc.keyPath, tc.keyPass) + if tc.wantErr != (err != nil) { + t.Errorf("NewFile() expected %t, got err %s", tc.wantErr, err) + } + }) + } +} diff --git a/pkg/signer/memory_test.go b/pkg/signer/memory_test.go index 6939dcba4..60d257947 100644 --- a/pkg/signer/memory_test.go +++ b/pkg/signer/memory_test.go @@ -24,7 +24,7 @@ import ( func TestMemory(t *testing.T) { ctx := context.Background() - m, err := New(ctx, "memory") + m, err := New(ctx, "memory", "") if err != nil { t.Fatalf("new memory: %v", err) } diff --git a/pkg/signer/signer.go b/pkg/signer/signer.go index 485d0cce2..481c184da 100644 --- a/pkg/signer/signer.go +++ b/pkg/signer/signer.go @@ -18,20 +18,19 @@ package signer import ( "context" - "fmt" "strings" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/kms/gcp" ) -func New(ctx context.Context, signer string) (signature.Signer, error) { +func New(ctx context.Context, signer string, pass string) (signature.Signer, error) { switch { case strings.HasPrefix(signer, gcp.ReferenceScheme): return gcp.LoadSignerVerifier(ctx, signer) case signer == MemoryScheme: return NewMemory() default: - return nil, fmt.Errorf("please provide a valid signer, %v is not valid", signer) + return NewFile(signer, pass) } }