Skip to content

Clean serialize.go #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,16 @@ func SetUpInstance(ctx context.Context, opts InstanceOptions) (*Instance, error)
return nil, fmt.Errorf("failed to parse RejectExtensions: %v", err)
}

logID, err := GetCTLogID(cfg.Signer.Public())
timeSource := new(SystemTimeSource)
cpSigner, err := NewCpSigner(cfg.Signer, cfg.Origin, timeSource)
if err != nil {
return nil, fmt.Errorf("failed to get logID for signing: %v", err)
return nil, fmt.Errorf("failed to create checkpoint signer: %v", err)
}
timeSource := new(SystemTimeSource)
ctSigner := NewCpSigner(cfg.Signer, cfg.Origin, logID, timeSource)

if opts.CreateStorage == nil {
return nil, fmt.Errorf("failed to initiate storage backend: nil createStorage")
}
storage, err := opts.CreateStorage(ctx, ctSigner)
storage, err := opts.CreateStorage(ctx, cpSigner)
if err != nil {
return nil, fmt.Errorf("failed to initiate storage backend: %v", err)
}
Expand Down
47 changes: 47 additions & 0 deletions modules/dedup/dedup.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ package dedup
import (
"bytes"
"context"
"crypto/sha256"
"errors"
"fmt"
"math"
"os"
"strconv"
"time"

"github.com/transparency-dev/trillian-tessera/client"
"golang.org/x/crypto/cryptobyte"
"k8s.io/klog/v2"
)

Expand Down Expand Up @@ -117,3 +120,47 @@ func sync(ctx context.Context, lds LocalBEDedupStorage, pb ParseBundleFunc, fcp
klog.V(3).Infof("LocalBEDEdup.sync(): dedup data synced to logsize %d", ckptSize)
return nil
}

// DedupFromBundle converts a bundle into an array of LeafDedupInfo.
//
// The index of a leaf is computed from its position in the log, instead of parsing SCTs.
// Greatly inspired by https://github.com/FiloSottile/sunlight/blob/main/tile.go
// TODO(phboneff): move this somewhere else, and only leave crypto in this file
func DedupFromBundle(bundle []byte, bundleIdx uint64) ([]LeafDedupInfo, error) {
kvs := []LeafDedupInfo{}
s := cryptobyte.String(bundle)

for i := bundleIdx * 256; len(s) > 0; i++ {
var timestamp uint64
var entryType uint16
var extensions, fingerprints cryptobyte.String
if !s.ReadUint64(&timestamp) || !s.ReadUint16(&entryType) || timestamp > math.MaxInt64 {
return nil, fmt.Errorf("invalid data tile")
}
crt := []byte{}
switch entryType {
case 0: // x509_entry
if !s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
!s.ReadUint16LengthPrefixed(&extensions) ||
!s.ReadUint16LengthPrefixed(&fingerprints) {
return nil, fmt.Errorf("invalid data tile x509_entry")
}
case 1: // precert_entry
IssuerKeyHash := [32]byte{}
var defangedCrt, extensions cryptobyte.String
if !s.CopyBytes(IssuerKeyHash[:]) ||
!s.ReadUint24LengthPrefixed(&defangedCrt) ||
!s.ReadUint16LengthPrefixed(&extensions) ||
!s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
!s.ReadUint16LengthPrefixed(&fingerprints) {
return nil, fmt.Errorf("invalid data tile precert_entry")
}
default:
return nil, fmt.Errorf("invalid data tile: unknown type %d", entryType)
}
k := sha256.Sum256(crt)
sctDedupInfo := SCTDedupInfo{Idx: uint64(i), Timestamp: timestamp}
kvs = append(kvs, LeafDedupInfo{LeafID: k[:], SCTDedupInfo: sctDedupInfo})
}
return kvs, nil
}
68 changes: 21 additions & 47 deletions serialize.go → signatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ import (
"crypto/sha256"
"encoding/binary"
"fmt"
"math"

"github.com/google/certificate-transparency-go/tls"
"github.com/google/certificate-transparency-go/x509"
"github.com/transparency-dev/formats/log"
"github.com/transparency-dev/static-ct/modules/dedup"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/mod/sumdb/note"

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

const millisPerNano int64 = 1000 * 1000
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't there approximately zero milliseconds per nanosecond, did you mean nanosPerMilli? :)

If so, could this be ... = time.Millisecond / time.Nanosecond?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe! This is not new code, I'm blindly migrating it from structures.go. Fixed!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(did you mean to also export it?)


// TODO(phboneff): create an SCTSigner object
func buildV1SCT(signer crypto.Signer, leaf *ct.MerkleTreeLeaf) (*ct.SignedCertificateTimestamp, error) {
// Serialize SCT signature input to get the bytes that need to be signed
sctInput := ct.SignedCertificateTimestamp{
Expand Down Expand Up @@ -159,62 +160,35 @@ func (cts *CpSigner) KeyHash() uint32 {

// NewCpSigner returns a new note signer that can sign https://c2sp.org/static-ct-api checkpoints.
// TODO(phboneff): add tests
func NewCpSigner(signer crypto.Signer, origin string, logID [32]byte, timeSource TimeSource) note.Signer {
func NewCpSigner(cs crypto.Signer, origin string, timeSource TimeSource) (note.Signer, error) {
logID, err := GetCTLogID(cs.Public())
if err != nil {
return nil, fmt.Errorf("failed to get logID for signing: %v", err)
}

h := sha256.New()
h.Write([]byte(origin))
h.Write([]byte{0x0A}) // newline
h.Write([]byte{0x05}) // signature type
h.Write(logID[:])
sum := h.Sum(nil)

ctSigner := &CpSigner{
sthSigner: signer,
ns := &CpSigner{
sthSigner: cs,
origin: origin,
keyHash: binary.BigEndian.Uint32(sum),
timeSource: timeSource,
}
return ctSigner

return ns, nil
}

// DedupFromBundle converts a bundle into an array of dedup.LeafDedupInfo.
//
// The index of a leaf is computed from its position in the log, instead of parsing SCTs.
// Greatly inspired by https://github.com/FiloSottile/sunlight/blob/main/tile.go
func DedupFromBundle(bundle []byte, bundleIdx uint64) ([]dedup.LeafDedupInfo, error) {
kvs := []dedup.LeafDedupInfo{}
s := cryptobyte.String(bundle)

for i := bundleIdx * 256; len(s) > 0; i++ {
var timestamp uint64
var entryType uint16
var extensions, fingerprints cryptobyte.String
if !s.ReadUint64(&timestamp) || !s.ReadUint16(&entryType) || timestamp > math.MaxInt64 {
return nil, fmt.Errorf("invalid data tile")
}
crt := []byte{}
switch entryType {
case 0: // x509_entry
if !s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
!s.ReadUint16LengthPrefixed(&extensions) ||
!s.ReadUint16LengthPrefixed(&fingerprints) {
return nil, fmt.Errorf("invalid data tile x509_entry")
}
case 1: // precert_entry
IssuerKeyHash := [32]byte{}
var defangedCrt, extensions cryptobyte.String
if !s.CopyBytes(IssuerKeyHash[:]) ||
!s.ReadUint24LengthPrefixed(&defangedCrt) ||
!s.ReadUint16LengthPrefixed(&extensions) ||
!s.ReadUint24LengthPrefixed((*cryptobyte.String)(&crt)) ||
!s.ReadUint16LengthPrefixed(&fingerprints) {
return nil, fmt.Errorf("invalid data tile precert_entry")
}
default:
return nil, fmt.Errorf("invalid data tile: unknown type %d", entryType)
}
k := sha256.Sum256(crt)
sctDedupInfo := dedup.SCTDedupInfo{Idx: uint64(i), Timestamp: timestamp}
kvs = append(kvs, dedup.LeafDedupInfo{LeafID: k[:], SCTDedupInfo: sctDedupInfo})
// GetCTLogID takes the key manager for a log and returns the LogID. (see RFC 6962 S3.2)
// In CT V1 the log id is a hash of the public key.
func GetCTLogID(pk crypto.PublicKey) ([sha256.Size]byte, error) {
pubBytes, err := x509.MarshalPKIXPublicKey(pk)
if err != nil {
return [sha256.Size]byte{}, err
}
return kvs, nil
return sha256.Sum256(pubBytes), nil
}
39 changes: 39 additions & 0 deletions serialize_test.go → signatures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@ package sctfe

import (
"bytes"
"crypto"
"crypto/sha256"
"encoding/pem"
"testing"
"time"

"github.com/google/certificate-transparency-go/tls"
"github.com/google/certificate-transparency-go/x509"
Expand All @@ -28,6 +31,13 @@ import (
ct "github.com/google/certificate-transparency-go"
)

var (
fixedTime = time.Date(2017, 9, 7, 12, 15, 23, 0, time.UTC)
fixedTimeMillis = uint64(fixedTime.UnixNano() / millisPerNano)
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}
fakeSignature = []byte("signed")
)

func TestBuildV1MerkleTreeLeafForCert(t *testing.T) {
cert, err := x509util.CertificateFromPEM([]byte(testdata.LeafSignedByFakeIntermediateCertPEM))
if x509.IsFatal(err) {
Expand Down Expand Up @@ -141,3 +151,32 @@ func TestSignV1SCTForPrecertificate(t *testing.T) {
t.Fatalf("TBS cert mismatch, got %v, expected %v", got, want)
}
}

func TestGetCTLogID(t *testing.T) {
block, _ := pem.Decode([]byte(testdata.DemoPublicKey))
pk, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
t.Fatalf("unexpected error loading public key: %v", err)
}

got, err := GetCTLogID(pk)
if err != nil {
t.Fatalf("error getting logid: %v", err)
}

if want := demoLogID; got != want {
t.Errorf("logID: \n%v want \n%v", got, want)
}
}

// Creates a fake signer for use in interaction tests.
// It will always return fakeSig when asked to sign something.
func setupSigner(fakeSig []byte) (crypto.Signer, error) {
block, _ := pem.Decode([]byte(testdata.DemoPublicKey))
key, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}

return testdata.NewSignerWithFixedSig(key, fakeSig), nil
}
37 changes: 0 additions & 37 deletions structures.go

This file was deleted.

61 changes: 0 additions & 61 deletions structures_test.go

This file was deleted.

Loading