Skip to content

Commit 0c2ba58

Browse files
authored
Clean serialize.go (#84)
* push GetCTLogID into NewCpSigner * move DedupFromBundle to dedup.go * merge structures.go into serialize.go * rename serialize.go to signatures.go * error handling * address comments 1/2 * leave todo * millis * unexport
1 parent 51c49d5 commit 0c2ba58

File tree

8 files changed

+115
-152
lines changed

8 files changed

+115
-152
lines changed

handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ func addChainInternal(ctx context.Context, li *logInfo, w http.ResponseWriter, r
312312
}
313313
// Get the current time in the form used throughout RFC6962, namely milliseconds since Unix
314314
// epoch, and use this throughout.
315-
timeMillis := uint64(li.TimeSource.Now().UnixNano() / millisPerNano)
315+
timeMillis := uint64(li.TimeSource.Now().UnixNano() / nanosPerMilli)
316316

317317
entry, err := entryFromChain(chain, isPrecert, timeMillis)
318318
if err != nil {

handlers_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import (
4949

5050
// Arbitrary time for use in tests
5151
var fakeTime = time.Date(2016, 7, 22, 11, 01, 13, 0, time.UTC)
52-
var fakeTimeMillis = uint64(fakeTime.UnixNano() / millisPerNano)
52+
var fakeTimeMillis = uint64(fakeTime.UnixNano() / nanosPerMilli)
5353

5454
// The deadline should be the above bumped by 500ms
5555
var fakeDeadlineTime = time.Date(2016, 7, 22, 11, 01, 13, 500*1000*1000, time.UTC)

instance.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,16 @@ func SetUpInstance(ctx context.Context, opts InstanceOptions) (*Instance, error)
8585
return nil, fmt.Errorf("failed to parse RejectExtensions: %v", err)
8686
}
8787

88-
logID, err := GetCTLogID(cfg.Signer.Public())
88+
timeSource := new(SystemTimeSource)
89+
cpSigner, err := NewCpSigner(cfg.Signer, cfg.Origin, timeSource)
8990
if err != nil {
90-
return nil, fmt.Errorf("failed to get logID for signing: %v", err)
91+
return nil, fmt.Errorf("failed to create checkpoint signer: %v", err)
9192
}
92-
timeSource := new(SystemTimeSource)
93-
ctSigner := NewCpSigner(cfg.Signer, cfg.Origin, logID, timeSource)
9493

9594
if opts.CreateStorage == nil {
9695
return nil, fmt.Errorf("failed to initiate storage backend: nil createStorage")
9796
}
98-
storage, err := opts.CreateStorage(ctx, ctSigner)
97+
storage, err := opts.CreateStorage(ctx, cpSigner)
9998
if err != nil {
10099
return nil, fmt.Errorf("failed to initiate storage backend: %v", err)
101100
}

modules/dedup/dedup.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ package dedup
1818
import (
1919
"bytes"
2020
"context"
21+
"crypto/sha256"
2122
"errors"
2223
"fmt"
24+
"math"
2325
"os"
2426
"strconv"
2527
"time"
2628

2729
"github.com/transparency-dev/trillian-tessera/client"
30+
"golang.org/x/crypto/cryptobyte"
2831
"k8s.io/klog/v2"
2932
)
3033

@@ -117,3 +120,47 @@ func sync(ctx context.Context, lds LocalBEDedupStorage, pb ParseBundleFunc, fcp
117120
klog.V(3).Infof("LocalBEDEdup.sync(): dedup data synced to logsize %d", ckptSize)
118121
return nil
119122
}
123+
124+
// DedupFromBundle converts a bundle into an array of LeafDedupInfo.
125+
//
126+
// The index of a leaf is computed from its position in the log, instead of parsing SCTs.
127+
// Greatly inspired by https://github.com/FiloSottile/sunlight/blob/main/tile.go
128+
// TODO(phboneff): move this somewhere else, and only leave crypto in this file
129+
func DedupFromBundle(bundle []byte, bundleIdx uint64) ([]LeafDedupInfo, error) {
130+
kvs := []LeafDedupInfo{}
131+
s := cryptobyte.String(bundle)
132+
133+
for i := bundleIdx * 256; len(s) > 0; i++ {
134+
var timestamp uint64
135+
var entryType uint16
136+
var extensions, fingerprints cryptobyte.String
137+
if !s.ReadUint64(&timestamp) || !s.ReadUint16(&entryType) || timestamp > math.MaxInt64 {
138+
return nil, fmt.Errorf("invalid data tile")
139+
}
140+
crt := []byte{}
141+
switch entryType {
142+
case 0: // x509_entry
143+
if !s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
144+
!s.ReadUint16LengthPrefixed(&extensions) ||
145+
!s.ReadUint16LengthPrefixed(&fingerprints) {
146+
return nil, fmt.Errorf("invalid data tile x509_entry")
147+
}
148+
case 1: // precert_entry
149+
IssuerKeyHash := [32]byte{}
150+
var defangedCrt, extensions cryptobyte.String
151+
if !s.CopyBytes(IssuerKeyHash[:]) ||
152+
!s.ReadUint24LengthPrefixed(&defangedCrt) ||
153+
!s.ReadUint16LengthPrefixed(&extensions) ||
154+
!s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
155+
!s.ReadUint16LengthPrefixed(&fingerprints) {
156+
return nil, fmt.Errorf("invalid data tile precert_entry")
157+
}
158+
default:
159+
return nil, fmt.Errorf("invalid data tile: unknown type %d", entryType)
160+
}
161+
k := sha256.Sum256(crt)
162+
sctDedupInfo := SCTDedupInfo{Idx: uint64(i), Timestamp: timestamp}
163+
kvs = append(kvs, LeafDedupInfo{LeafID: k[:], SCTDedupInfo: sctDedupInfo})
164+
}
165+
return kvs, nil
166+
}

serialize.go renamed to signatures.go

Lines changed: 23 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@ import (
2020
"crypto/sha256"
2121
"encoding/binary"
2222
"fmt"
23-
"math"
23+
"time"
2424

2525
"github.com/google/certificate-transparency-go/tls"
26+
"github.com/google/certificate-transparency-go/x509"
2627
"github.com/transparency-dev/formats/log"
27-
"github.com/transparency-dev/static-ct/modules/dedup"
28-
"golang.org/x/crypto/cryptobyte"
2928
"golang.org/x/mod/sumdb/note"
3029

3130
ct "github.com/google/certificate-transparency-go"
3231
)
3332

33+
const nanosPerMilli int64 = int64(time.Millisecond / time.Nanosecond)
34+
35+
// TODO(phboneff): create an SCTSigner object
3436
func buildV1SCT(signer crypto.Signer, leaf *ct.MerkleTreeLeaf) (*ct.SignedCertificateTimestamp, error) {
3537
// Serialize SCT signature input to get the bytes that need to be signed
3638
sctInput := ct.SignedCertificateTimestamp{
@@ -159,62 +161,36 @@ func (cts *CpSigner) KeyHash() uint32 {
159161

160162
// NewCpSigner returns a new note signer that can sign https://c2sp.org/static-ct-api checkpoints.
161163
// TODO(phboneff): add tests
162-
func NewCpSigner(signer crypto.Signer, origin string, logID [32]byte, timeSource TimeSource) note.Signer {
164+
func NewCpSigner(cs crypto.Signer, origin string, timeSource TimeSource) (note.Signer, error) {
165+
logID, err := GetCTLogID(cs.Public())
166+
if err != nil {
167+
return nil, fmt.Errorf("failed to get logID for signing: %v", err)
168+
}
169+
163170
h := sha256.New()
164171
h.Write([]byte(origin))
165172
h.Write([]byte{0x0A}) // newline
166173
h.Write([]byte{0x05}) // signature type
167174
h.Write(logID[:])
168175
sum := h.Sum(nil)
169176

170-
ctSigner := &CpSigner{
171-
sthSigner: signer,
177+
ns := &CpSigner{
178+
sthSigner: cs,
172179
origin: origin,
173180
keyHash: binary.BigEndian.Uint32(sum),
174181
timeSource: timeSource,
175182
}
176-
return ctSigner
183+
184+
return ns, nil
177185
}
178186

179-
// DedupFromBundle converts a bundle into an array of dedup.LeafDedupInfo.
180-
//
181-
// The index of a leaf is computed from its position in the log, instead of parsing SCTs.
182-
// Greatly inspired by https://github.com/FiloSottile/sunlight/blob/main/tile.go
183-
func DedupFromBundle(bundle []byte, bundleIdx uint64) ([]dedup.LeafDedupInfo, error) {
184-
kvs := []dedup.LeafDedupInfo{}
185-
s := cryptobyte.String(bundle)
186-
187-
for i := bundleIdx * 256; len(s) > 0; i++ {
188-
var timestamp uint64
189-
var entryType uint16
190-
var extensions, fingerprints cryptobyte.String
191-
if !s.ReadUint64(&timestamp) || !s.ReadUint16(&entryType) || timestamp > math.MaxInt64 {
192-
return nil, fmt.Errorf("invalid data tile")
193-
}
194-
crt := []byte{}
195-
switch entryType {
196-
case 0: // x509_entry
197-
if !s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
198-
!s.ReadUint16LengthPrefixed(&extensions) ||
199-
!s.ReadUint16LengthPrefixed(&fingerprints) {
200-
return nil, fmt.Errorf("invalid data tile x509_entry")
201-
}
202-
case 1: // precert_entry
203-
IssuerKeyHash := [32]byte{}
204-
var defangedCrt, extensions cryptobyte.String
205-
if !s.CopyBytes(IssuerKeyHash[:]) ||
206-
!s.ReadUint24LengthPrefixed(&defangedCrt) ||
207-
!s.ReadUint16LengthPrefixed(&extensions) ||
208-
!s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
209-
!s.ReadUint16LengthPrefixed(&fingerprints) {
210-
return nil, fmt.Errorf("invalid data tile precert_entry")
211-
}
212-
default:
213-
return nil, fmt.Errorf("invalid data tile: unknown type %d", entryType)
214-
}
215-
k := sha256.Sum256(crt)
216-
sctDedupInfo := dedup.SCTDedupInfo{Idx: uint64(i), Timestamp: timestamp}
217-
kvs = append(kvs, dedup.LeafDedupInfo{LeafID: k[:], SCTDedupInfo: sctDedupInfo})
187+
// GetCTLogID takes a log public key and returns the LogID. (see RFC 6962 S3.2)
188+
// In CT V1 the log id is a hash of the public key.
189+
// TODO(phboneff): migrate to the logid package
190+
func GetCTLogID(pk crypto.PublicKey) ([sha256.Size]byte, error) {
191+
pubBytes, err := x509.MarshalPKIXPublicKey(pk)
192+
if err != nil {
193+
return [sha256.Size]byte{}, err
218194
}
219-
return kvs, nil
195+
return sha256.Sum256(pubBytes), nil
220196
}

serialize_test.go renamed to signatures_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@ package sctfe
1616

1717
import (
1818
"bytes"
19+
"crypto"
1920
"crypto/sha256"
21+
"encoding/pem"
2022
"testing"
23+
"time"
2124

2225
"github.com/google/certificate-transparency-go/tls"
2326
"github.com/google/certificate-transparency-go/x509"
@@ -28,6 +31,13 @@ import (
2831
ct "github.com/google/certificate-transparency-go"
2932
)
3033

34+
var (
35+
fixedTime = time.Date(2017, 9, 7, 12, 15, 23, 0, time.UTC)
36+
fixedTimeMillis = uint64(fixedTime.UnixNano() / nanosPerMilli)
37+
demoLogID = [32]byte{19, 56, 222, 93, 229, 36, 102, 128, 227, 214, 3, 121, 93, 175, 126, 236, 97, 217, 34, 32, 40, 233, 98, 27, 46, 179, 164, 251, 84, 10, 60, 57}
38+
fakeSignature = []byte("signed")
39+
)
40+
3141
func TestBuildV1MerkleTreeLeafForCert(t *testing.T) {
3242
cert, err := x509util.CertificateFromPEM([]byte(testdata.LeafSignedByFakeIntermediateCertPEM))
3343
if x509.IsFatal(err) {
@@ -141,3 +151,32 @@ func TestSignV1SCTForPrecertificate(t *testing.T) {
141151
t.Fatalf("TBS cert mismatch, got %v, expected %v", got, want)
142152
}
143153
}
154+
155+
func TestGetCTLogID(t *testing.T) {
156+
block, _ := pem.Decode([]byte(testdata.DemoPublicKey))
157+
pk, err := x509.ParsePKIXPublicKey(block.Bytes)
158+
if err != nil {
159+
t.Fatalf("unexpected error loading public key: %v", err)
160+
}
161+
162+
got, err := GetCTLogID(pk)
163+
if err != nil {
164+
t.Fatalf("error getting logid: %v", err)
165+
}
166+
167+
if want := demoLogID; got != want {
168+
t.Errorf("logID: \n%v want \n%v", got, want)
169+
}
170+
}
171+
172+
// Creates a fake signer for use in interaction tests.
173+
// It will always return fakeSig when asked to sign something.
174+
func setupSigner(fakeSig []byte) (crypto.Signer, error) {
175+
block, _ := pem.Decode([]byte(testdata.DemoPublicKey))
176+
key, err := x509.ParsePKIXPublicKey(block.Bytes)
177+
if err != nil {
178+
return nil, err
179+
}
180+
181+
return testdata.NewSignerWithFixedSig(key, fakeSig), nil
182+
}

structures.go

Lines changed: 0 additions & 37 deletions
This file was deleted.

structures_test.go

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)