Skip to content

Commit cfb395d

Browse files
authored
Use an in memory timestamping key (sigstore#402)
* use an in memory timestamping key Signed-off-by: Asra Ali <asraa@google.com> * address comments Signed-off-by: Asra Ali <asraa@google.com>
1 parent 71ed018 commit cfb395d

File tree

9 files changed

+164
-91
lines changed

9 files changed

+164
-91
lines changed

cmd/rekor-server/app/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func init() {
6262
rootCmd.PersistentFlags().String("rekor_server.hostname", "rekor.sigstore.dev", "public hostname of instance")
6363
rootCmd.PersistentFlags().String("rekor_server.address", "127.0.0.1", "Address to bind to")
6464
rootCmd.PersistentFlags().String("rekor_server.signer", "memory", "Rekor signer to use. Current valid options include: [gcpkms, memory]")
65-
rootCmd.PersistentFlags().String("rekor_server.timestamp_chain", "", "PEM encoded cert chain to use for timestamping")
65+
rootCmd.PersistentFlags().String("rekor_server.timestamp_chain", "", "PEM encoded cert chain signing authorizing the signer to be a CA to sign a timestamping cert")
6666

6767
rootCmd.PersistentFlags().Uint16("port", 3000, "Port to bind to")
6868

go.mod

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/sigstore/rekor
33
go 1.16
44

55
require (
6+
cloud.google.com/go v0.89.0 // indirect
67
cloud.google.com/go/storage v1.16.0 // indirect
78
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
89
github.com/blang/semver v3.5.1+incompatible
@@ -12,7 +13,9 @@ require (
1213
github.com/danieljoos/wincred v1.1.1 // indirect
1314
github.com/ghodss/yaml v1.0.0
1415
github.com/go-chi/chi v4.1.2+incompatible
16+
github.com/go-openapi/analysis v0.20.1 // indirect
1517
github.com/go-openapi/errors v0.20.0
18+
github.com/go-openapi/jsonreference v0.19.6 // indirect
1619
github.com/go-openapi/loads v0.20.2
1720
github.com/go-openapi/runtime v0.19.29
1821
github.com/go-openapi/spec v0.20.3
@@ -24,37 +27,42 @@ require (
2427
github.com/google/go-cmp v0.5.6
2528
github.com/google/rpmpack v0.0.0-20210518075352-dc539ef4f2ea
2629
github.com/google/trillian v1.3.14-0.20210713114448-df474653733c
30+
github.com/google/uuid v1.3.0 // indirect
2731
github.com/in-toto/in-toto-golang v0.2.1-0.20210627200632-886210ae2ab9
2832
github.com/jedisct1/go-minisign v0.0.0-20210703085342-c1f07ee84431
2933
github.com/leodido/go-urn v1.2.1 // indirect
34+
github.com/mailru/easyjson v0.7.7 // indirect
3035
github.com/mediocregopher/radix/v4 v4.0.0-beta.1
3136
github.com/mitchellh/go-homedir v1.1.0
3237
github.com/mitchellh/mapstructure v1.4.1
3338
github.com/pkg/errors v0.9.1
3439
github.com/prometheus/client_golang v1.11.0
35-
github.com/prometheus/common v0.29.0 // indirect
36-
github.com/prometheus/procfs v0.7.0 // indirect
40+
github.com/prometheus/common v0.30.0 // indirect
41+
github.com/prometheus/procfs v0.7.1 // indirect
3742
github.com/rs/cors v1.8.0
3843
github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74
39-
github.com/sigstore/sigstore v0.0.0-20210713222344-1fee53516622
44+
github.com/sigstore/sigstore v0.0.0-20210729211320-56a91f560f44
45+
github.com/spf13/cast v1.4.0 // indirect
4046
github.com/spf13/cobra v1.2.1
4147
github.com/spf13/pflag v1.0.5
4248
github.com/spf13/viper v1.8.1
49+
github.com/tidwall/pretty v1.2.0 // indirect
4350
github.com/tilinna/clock v1.1.0 // indirect
4451
github.com/ulikunitz/xz v0.5.10 // indirect
4552
github.com/urfave/negroni v1.0.0
4653
github.com/zalando/go-keyring v0.1.1 // indirect
47-
go.uber.org/atomic v1.8.0 // indirect
54+
go.mongodb.org/mongo-driver v1.7.0 // indirect
55+
go.uber.org/atomic v1.9.0 // indirect
4856
go.uber.org/goleak v1.1.10
4957
go.uber.org/multierr v1.7.0 // indirect
5058
go.uber.org/zap v1.18.1
5159
gocloud.dev v0.23.0
5260
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
5361
golang.org/x/mod v0.4.2
54-
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
62+
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
5563
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
56-
golang.org/x/tools v0.1.5 // indirect
57-
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a
64+
google.golang.org/api v0.52.0 // indirect
65+
google.golang.org/genproto v0.0.0-20210729151513-df9385d47c1b
5866
google.golang.org/grpc v1.39.0
5967
google.golang.org/protobuf v1.27.1
6068
gopkg.in/ini.v1 v1.62.0

go.sum

Lines changed: 41 additions & 34 deletions
Large diffs are not rendered by default.

pkg/api/api.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type API struct {
5858
pubkey string // PEM encoded public key
5959
pubkeyHash string // SHA256 hash of DER-encoded public key
6060
signer signature.Signer
61+
tsaSigner signature.Signer // the signer to use for timestamping
6162
certChain []*x509.Certificate // timestamping cert chain
6263
certChainPem string // PEM encoded timestamping cert chain
6364
verifier *client.LogVerifier
@@ -112,6 +113,16 @@ func NewAPI() (*API, error) {
112113
return nil, errors.Wrap(err, "new verifier")
113114
}
114115

116+
// Use an in-memory key for timestamping
117+
tsaSigner, err := signer.New(ctx, signer.MemoryScheme)
118+
if err != nil {
119+
return nil, errors.Wrap(err, "getting new tsa signer")
120+
}
121+
tsaPk, err := tsaSigner.PublicKey(options.WithContext(ctx))
122+
if err != nil {
123+
return nil, errors.Wrap(err, "getting public key")
124+
}
125+
115126
var certChain []*x509.Certificate
116127
b64CertChainStr := viper.GetString("rekor_server.timestamp_chain")
117128
if b64CertChainStr != "" {
@@ -122,15 +133,13 @@ func NewAPI() (*API, error) {
122133
if certChain, err = pki.ParseTimestampCertChain([]byte(certChainStr)); err != nil {
123134
return nil, errors.Wrap(err, "parsing timestamp cert chain")
124135
}
125-
} else if viper.GetString("rekor_server.signer") == signer.MemoryScheme {
126-
// Generate a timestaming cert with a self signed CA if we are configured with an in-memory signer.
127-
var err error
128-
certChain, err = signer.NewTimestampingCertWithSelfSignedCA(pk)
129-
if err != nil {
130-
return nil, errors.Wrap(err, "generating timestaping cert chain")
131-
}
132136
}
133137

138+
// Generate a tsa certificate from the rekor signer and provided certificate chain
139+
certChain, err = signer.NewTimestampingCertWithChain(ctx, tsaPk, rekorSigner, certChain)
140+
if err != nil {
141+
return nil, errors.Wrap(err, "generating timestamping cert chain")
142+
}
134143
certChainPem, err := pki.CertChainToPEM(certChain)
135144
if err != nil {
136145
return nil, errors.Wrap(err, "timestamping cert chain")
@@ -142,6 +151,7 @@ func NewAPI() (*API, error) {
142151
pubkey: string(pubkey),
143152
pubkeyHash: hex.EncodeToString(pubkeyHashBytes[:]),
144153
signer: rekorSigner,
154+
tsaSigner: tsaSigner,
145155
certChain: certChain,
146156
certChainPem: string(certChainPem),
147157
verifier: verifier,

pkg/api/timestamp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import (
3333
)
3434

3535
func RequestFromRekor(ctx context.Context, req pkcs9.TimeStampReq) ([]byte, error) {
36-
resp, err := util.CreateRfc3161Response(ctx, req, api.certChain, api.signer)
36+
resp, err := util.CreateRfc3161Response(ctx, req, api.certChain, api.tsaSigner)
3737
if err != nil {
3838
return nil, err
3939
}

pkg/pki/x509/x509_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,17 +205,22 @@ func TestNilCertChainToPEM(t *testing.T) {
205205
}
206206

207207
func TestCertChain_Verify(t *testing.T) {
208-
mem, err := signer.NewMemory()
208+
caSigner, err := signer.NewMemory()
209209
if err != nil {
210210
t.Fatal(err)
211211
}
212212
// A properly created cert chain should encode to PEM OK.
213213
ctx := context.Background()
214+
mem, err := signer.NewMemory()
215+
if err != nil {
216+
t.Fatal(err)
217+
}
214218
pk, err := mem.PublicKey(options.WithContext(ctx))
215219
if err != nil {
216220
t.Fatal(err)
217221
}
218-
certChain, err := signer.NewTimestampingCertWithSelfSignedCA(pk)
222+
223+
certChain, err := signer.NewTimestampingCertWithChain(ctx, pk, caSigner, nil)
219224
if err != nil {
220225
t.Fatal(err)
221226
}

pkg/signer/memory.go

Lines changed: 66 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ limitations under the License.
1717
package signer
1818

1919
import (
20+
"context"
2021
"crypto"
21-
"crypto/ecdsa"
2222
"crypto/elliptic"
2323
"crypto/rand"
2424
"crypto/x509"
@@ -30,6 +30,8 @@ import (
3030

3131
"github.com/pkg/errors"
3232
"github.com/sigstore/sigstore/pkg/signature"
33+
"github.com/sigstore/sigstore/pkg/signature/kms/gcp"
34+
"github.com/sigstore/sigstore/pkg/signature/options"
3335
)
3436

3537
const MemoryScheme = "memory"
@@ -39,33 +41,48 @@ type Memory struct {
3941
signature.ECDSASignerVerifier
4042
}
4143

42-
// create a self-signed CA and generate a timestamping certificate to rekor
43-
func NewTimestampingCertWithSelfSignedCA(pub crypto.PublicKey) ([]*x509.Certificate, error) {
44-
// generate self-signed CA
45-
caPrivKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
44+
// Generate a timestamping certificate for pub using the signer. The chain must verify the signer's public key if provided.
45+
// Otherwise, a self-signed root CA will be generated.
46+
func NewTimestampingCertWithChain(ctx context.Context, pub crypto.PublicKey, signer signature.Signer, chain []*x509.Certificate) ([]*x509.Certificate, error) {
47+
// Get the signer's (rekor's) public key
48+
signerPubKey, err := signer.PublicKey(options.WithContext(ctx))
4649
if err != nil {
47-
return nil, errors.Wrap(err, "generating private key")
50+
return nil, err
4851
}
49-
ca := &x509.Certificate{
50-
SerialNumber: big.NewInt(2019),
51-
Subject: pkix.Name{
52-
Organization: []string{"Root CA Test"},
53-
Country: []string{"US"},
54-
Province: []string{""},
55-
Locality: []string{"San Francisco"},
56-
StreetAddress: []string{"Golden Gate Bridge"},
57-
PostalCode: []string{"94016"},
58-
},
59-
NotBefore: time.Now(),
60-
NotAfter: time.Now().AddDate(10, 0, 0),
61-
IsCA: true,
62-
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageContentCommitment | x509.KeyUsageCertSign,
63-
BasicConstraintsValid: true,
52+
53+
// If the signer is not in-memory, retrieve the crypto.Signer
54+
var cryptoSigner crypto.Signer
55+
if s, ok := signer.(*gcp.SignerVerifier); ok {
56+
if cryptoSigner, _, err = s.CryptoSigner(ctx, func(err error) {}); err != nil {
57+
return nil, errors.Wrap(err, "getting kms signer")
58+
}
59+
} else {
60+
cryptoSigner = signer.(crypto.Signer)
6461
}
65-
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey)
66-
if err != nil {
67-
return nil, err
62+
63+
if len(chain) == 0 {
64+
// Generate an in-memory self-signed root CA.
65+
ca := &x509.Certificate{
66+
SerialNumber: big.NewInt(2019),
67+
Subject: pkix.Name{
68+
Organization: []string{"rekor in-memory root CA"},
69+
},
70+
NotBefore: time.Now(),
71+
NotAfter: time.Now().AddDate(10, 0, 0),
72+
IsCA: true,
73+
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageContentCommitment | x509.KeyUsageCertSign,
74+
BasicConstraintsValid: true,
75+
}
76+
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, signerPubKey, cryptoSigner)
77+
if err != nil {
78+
return nil, errors.Wrap(err, "creating self-signed CA")
79+
}
80+
chain, err = x509.ParseCertificates(caBytes)
81+
if err != nil {
82+
return nil, err
83+
}
6884
}
85+
6986
timestampExt, err := asn1.Marshal([]asn1.ObjectIdentifier{{1, 3, 6, 1, 5, 5, 7, 3, 8}})
7087
if err != nil {
7188
return nil, err
@@ -74,12 +91,7 @@ func NewTimestampingCertWithSelfSignedCA(pub crypto.PublicKey) ([]*x509.Certific
7491
cert := &x509.Certificate{
7592
SerialNumber: big.NewInt(1658),
7693
Subject: pkix.Name{
77-
Organization: []string{"Rekor Test"},
78-
Country: []string{"US"},
79-
Province: []string{""},
80-
Locality: []string{"San Francisco"},
81-
StreetAddress: []string{"Golden Gate Bridge"},
82-
PostalCode: []string{"94016"},
94+
Organization: []string{"Rekor Timestamping Cert"},
8395
},
8496
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
8597
NotBefore: time.Now(),
@@ -97,11 +109,33 @@ func NewTimestampingCertWithSelfSignedCA(pub crypto.PublicKey) ([]*x509.Certific
97109
},
98110
BasicConstraintsValid: true,
99111
}
100-
certBytes, err := x509.CreateCertificate(rand.Reader, cert, ca, pub.(*ecdsa.PublicKey), caPrivKey)
112+
113+
// Create the certificate
114+
certBytes, err := x509.CreateCertificate(rand.Reader, cert, chain[0], pub, cryptoSigner)
101115
if err != nil {
116+
return nil, errors.Wrap(err, "creating tsa certificate")
117+
}
118+
tsaCert, err := x509.ParseCertificates(certBytes)
119+
if err != nil {
120+
return nil, err
121+
}
122+
123+
// Verify and return the certificate chain
124+
root := x509.NewCertPool()
125+
root.AddCert(chain[len(chain)-1])
126+
intermediates := x509.NewCertPool()
127+
for _, intermediate := range chain[:len(chain)-1] {
128+
intermediates.AddCert(intermediate)
129+
}
130+
verifyOptions := x509.VerifyOptions{
131+
Roots: root,
132+
Intermediates: intermediates,
133+
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageTimeStamping},
134+
}
135+
if _, err = tsaCert[0].Verify(verifyOptions); err != nil {
102136
return nil, err
103137
}
104-
return x509.ParseCertificates(append(certBytes, caBytes...))
138+
return append(tsaCert, chain...), nil
105139
}
106140

107141
func NewMemory() (*Memory, error) {

pkg/signer/memory_test.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,21 @@ func TestMemory(t *testing.T) {
3434
if err != nil {
3535
t.Fatalf("new memory: %v", err)
3636
}
37+
tsaKey, err := New(ctx, "memory")
38+
if err != nil {
39+
t.Fatalf("new memory: %v", err)
40+
}
41+
3742
payload := []byte("payload")
3843

39-
// sign a payload
40-
sig, err := m.SignMessage(bytes.NewReader(payload), options.WithContext(ctx))
44+
// sign a payload with the tsa key
45+
sig, err := tsaKey.SignMessage(bytes.NewReader(payload), options.WithContext(ctx))
4146
if err != nil {
4247
t.Fatalf("signing payload: %v", err)
4348
}
4449

4550
// verify the signature against public key
46-
pubKey, err := m.PublicKey(options.WithContext(ctx))
51+
pubKey, err := tsaKey.PublicKey(options.WithContext(ctx))
4752
if err != nil {
4853
t.Fatalf("public key: %v", err)
4954
}
@@ -58,7 +63,7 @@ func TestMemory(t *testing.T) {
5863
}
5964

6065
// verify signature using the cert's public key
61-
certChain, err := NewTimestampingCertWithSelfSignedCA(pubKey)
66+
certChain, err := NewTimestampingCertWithChain(ctx, pubKey, m, nil)
6267
if err != nil {
6368
t.Fatalf("generating timestamping cert: %v", err)
6469
}

pkg/util/rfc3161_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,15 @@ func TestCreateRFC3161Response(t *testing.T) {
132132
if err != nil {
133133
t.Error(err)
134134
}
135-
pk, err := mem.PublicKey(options.WithContext(ctx))
135+
tsa, err := signer.NewMemory()
136+
if err != nil {
137+
t.Error(err)
138+
}
139+
pk, err := tsa.PublicKey(options.WithContext(ctx))
136140
if err != nil {
137141
t.Fatal(err)
138142
}
139-
certChain, err := signer.NewTimestampingCertWithSelfSignedCA(pk)
143+
certChain, err := signer.NewTimestampingCertWithChain(ctx, pk, mem, nil)
140144
if err != nil {
141145
t.Error(err)
142146
}
@@ -154,7 +158,7 @@ func TestCreateRFC3161Response(t *testing.T) {
154158
t.Error(err)
155159
}
156160

157-
resp, err := CreateRfc3161Response(ctx, *req, certChain, mem)
161+
resp, err := CreateRfc3161Response(ctx, *req, certChain, tsa)
158162
if err != nil {
159163
t.Error(err)
160164
}

0 commit comments

Comments
 (0)