Skip to content

Move code inside internal directory #102

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 8 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from 6 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
5 changes: 3 additions & 2 deletions cmd/gcp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/google/trillian/monitoring/opencensus"
"github.com/prometheus/client_golang/prometheus/promhttp"
sctfe "github.com/transparency-dev/static-ct"
"github.com/transparency-dev/static-ct/storage"
gcpSCTFE "github.com/transparency-dev/static-ct/storage/gcp"
tessera "github.com/transparency-dev/trillian-tessera"
gcpTessera "github.com/transparency-dev/trillian-tessera/storage/gcp"
Expand Down Expand Up @@ -167,7 +168,7 @@ func awaitSignal(doneFn func()) {
doneFn()
}

func newGCPStorage(ctx context.Context, signer note.Signer) (*sctfe.CTStorage, error) {
func newGCPStorage(ctx context.Context, signer note.Signer) (*storage.CTStorage, error) {
if *bucket == "" {
return nil, errors.New("missing bucket")
}
Expand Down Expand Up @@ -196,7 +197,7 @@ func newGCPStorage(ctx context.Context, signer note.Signer) (*sctfe.CTStorage, e
return nil, fmt.Errorf("failed to initialize GCP Spanner deduplication database: %v", err)
}

return sctfe.NewCTSTorage(tesseraStorage, issuerStorage, beDedupStorage)
return storage.NewCTStorage(tesseraStorage, issuerStorage, beDedupStorage)
}

type timestampFlag struct {
Expand Down
163 changes: 32 additions & 131 deletions ctlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,15 @@ package sctfe
import (
"context"
"crypto"
"crypto/ecdsa"
"errors"
"fmt"
"net/http"
"strconv"
"strings"
"time"

ct "github.com/google/certificate-transparency-go"
"github.com/google/certificate-transparency-go/asn1"
"github.com/google/certificate-transparency-go/x509"
"github.com/google/certificate-transparency-go/x509util"
"golang.org/x/mod/sumdb/note"
"k8s.io/klog/v2"
"github.com/transparency-dev/static-ct/internal/scti"
"github.com/transparency-dev/static-ct/storage"
)

// ChainValidationConfig contains parameters to configure chain validation.
Expand Down Expand Up @@ -65,74 +60,19 @@ type ChainValidationConfig struct {
NotAfterLimit *time.Time
}

// CreateStorage instantiates a Tessera storage implementation with a signer option.
type CreateStorage func(context.Context, note.Signer) (*CTStorage, error)

// log offers all the primitives necessary to run a static-ct-api log.
// TODO(phboneff): consider moving to methods when refactoring logInfo.
type log 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
// signSCT Signs SCTs.
signSCT signSCT
// chainValidationOpts contains various parameters for certificate chain
// validation.
chainValidationOpts chainValidationOpts
// storage stores certificate data.
storage Storage
}

var sysTimeSource = SystemTimeSource{}

// newLog instantiates a new log instance, with write endpoints.
// It initiates chain validation to validate writes, and storage to persist
// chains.
func newLog(ctx context.Context, origin string, signer crypto.Signer, cfg ChainValidationConfig, cs CreateStorage) (*log, error) {
log := &log{}

if origin == "" {
return nil, errors.New("empty origin")
}
log.origin = origin
// systemTimeSource implments scti.TimeSource.
type systemTimeSource struct{}

// Validate signer that only ECDSA is supported.
if signer == nil {
return nil, errors.New("empty signer")
}
switch keyType := signer.Public().(type) {
case *ecdsa.PublicKey:
default:
return nil, fmt.Errorf("unsupported key type: %v", keyType)
}

log.signSCT = func(leaf *ct.MerkleTreeLeaf) (*ct.SignedCertificateTimestamp, error) {
return buildV1SCT(signer, leaf)
}

vlc, err := newCertValidationOpts(cfg)
if err != nil {
return nil, fmt.Errorf("invalid cert validation config: %v", err)
}
log.chainValidationOpts = *vlc

cpSigner, err := newCpSigner(signer, origin, sysTimeSource)
if err != nil {
klog.Exitf("failed to create checkpoint Signer: %v", err)
}

storage, err := cs(ctx, cpSigner)
if err != nil {
klog.Exitf("failed to initiate storage backend: %v", err)
}
log.storage = storage

return log, nil
// Now returns the true current local time.
func (s systemTimeSource) Now() time.Time {
return time.Now()
}

var sysTimeSource = systemTimeSource{}

// newCertValidationOpts checks that a chain validation config is valid,
// parses it, and loads resources to validate chains.
func newCertValidationOpts(cfg ChainValidationConfig) (*chainValidationOpts, error) {
func newCertValidationOpts(cfg ChainValidationConfig) (*scti.ChainValidationOpts, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could this go in scti too?
Similarly, it's creating and returning structs defined in scti and looks quite like it's part of that package, and I think you wouldn't need to export ChainValidationOpts if it were in there since it's really just an internal detail of Log(?)

Actually, that'd potentially reduce the size of this PR quite a lot since many of the changed lines are just flipping the case of newly exported structs and fields & references to them.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This one is a bit harder to move: the Config struct has to be defined somewhere that's visible to external libraries.

Eventually, this options are used to call validateChain(chain, options). I think the right thing to do is to re-architecture the code for it to call methods (see TODO). I'll come to this later. This is specifically cumbersome to do for this one because these options are also used for the getRoots endpoint.... which is already a tricky one to handle with the x509 migration. So one step at a time :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

What I've done though, is to move the OID and ExtKeyUsage parsing functions to chain_validation.go

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In the meantime, to make this PR easier to digest, I can add a constructor in internal. That will save the PR from all the lowercase-->uppercase changes.

// Load the trusted roots.
if cfg.RootsPEMFile == "" {
return nil, errors.New("empty rootsPemFile")
Expand All @@ -151,39 +91,28 @@ func newCertValidationOpts(cfg ChainValidationConfig) (*chainValidationOpts, err
return nil, fmt.Errorf("'Not After' limit %q before start %q", cfg.NotAfterLimit.Format(time.RFC3339), cfg.NotAfterStart.Format(time.RFC3339))
}

validationOpts := chainValidationOpts{
trustedRoots: roots,
rejectExpired: cfg.RejectExpired,
rejectUnexpired: cfg.RejectUnexpired,
notAfterStart: cfg.NotAfterStart,
notAfterLimit: cfg.NotAfterLimit,
validationOpts := scti.ChainValidationOpts{
TrustedRoots: roots,
RejectExpired: cfg.RejectExpired,
RejectUnexpired: cfg.RejectUnexpired,
NotAfterStart: cfg.NotAfterStart,
NotAfterLimit: cfg.NotAfterLimit,
}

var err error
// Filter which extended key usages are allowed.
lExtKeyUsages := []string{}
if cfg.ExtKeyUsages != "" {
lExtKeyUsages = strings.Split(cfg.ExtKeyUsages, ",")
}
// Validate the extended key usages list.
for _, kuStr := range lExtKeyUsages {
if ku, ok := stringToKeyUsage[kuStr]; ok {
// If "Any" is specified, then we can ignore the entire list and
// just disable EKU checking.
if ku == x509.ExtKeyUsageAny {
klog.Info("Found ExtKeyUsageAny, allowing all EKUs")
validationOpts.extKeyUsages = nil
break
}
validationOpts.extKeyUsages = append(validationOpts.extKeyUsages, ku)
} else {
return nil, fmt.Errorf("unknown extended key usage: %s", kuStr)
lExtKeyUsages := strings.Split(cfg.ExtKeyUsages, ",")
validationOpts.ExtKeyUsages, err = scti.ParseExtKeyUsages(lExtKeyUsages)
if err != nil {
return nil, fmt.Errorf("failed to parse ExtKeyUsages: %v", err)
}
}

// Filter which extensions are rejected.
var err error
if cfg.RejectExtensions != "" {
lRejectExtensions := strings.Split(cfg.RejectExtensions, ",")
validationOpts.rejectExtIds, err = parseOIDs(lRejectExtensions)
validationOpts.RejectExtIds, err = scti.ParseOIDs(lRejectExtensions)
if err != nil {
return nil, fmt.Errorf("failed to parse RejectExtensions: %v", err)
}
Expand All @@ -192,55 +121,27 @@ func newCertValidationOpts(cfg ChainValidationConfig) (*chainValidationOpts, err
return &validationOpts, nil
}

func parseOIDs(oids []string) ([]asn1.ObjectIdentifier, error) {
ret := make([]asn1.ObjectIdentifier, 0, len(oids))
for _, s := range oids {
bits := strings.Split(s, ".")
var oid asn1.ObjectIdentifier
for _, n := range bits {
p, err := strconv.Atoi(n)
if err != nil {
return nil, err
}
oid = append(oid, p)
}
ret = append(ret, oid)
}
return ret, nil
}

var stringToKeyUsage = map[string]x509.ExtKeyUsage{
"Any": x509.ExtKeyUsageAny,
"ServerAuth": x509.ExtKeyUsageServerAuth,
"ClientAuth": x509.ExtKeyUsageClientAuth,
"CodeSigning": x509.ExtKeyUsageCodeSigning,
"EmailProtection": x509.ExtKeyUsageEmailProtection,
"IPSECEndSystem": x509.ExtKeyUsageIPSECEndSystem,
"IPSECTunnel": x509.ExtKeyUsageIPSECTunnel,
"IPSECUser": x509.ExtKeyUsageIPSECUser,
"TimeStamping": x509.ExtKeyUsageTimeStamping,
"OCSPSigning": x509.ExtKeyUsageOCSPSigning,
"MicrosoftServerGatedCrypto": x509.ExtKeyUsageMicrosoftServerGatedCrypto,
"NetscapeServerGatedCrypto": x509.ExtKeyUsageNetscapeServerGatedCrypto,
}

// NewLogHandler creates a Tessera based CT log pluged into HTTP handlers.
// The HTTP server handlers implement https://c2sp.org/static-ct-api write
// endpoints.
func NewLogHandler(ctx context.Context, origin string, signer crypto.Signer, cfg ChainValidationConfig, cs CreateStorage, httpDeadline time.Duration, maskInternalErrors bool) (http.Handler, error) {
log, err := newLog(ctx, origin, signer, cfg, cs)
func NewLogHandler(ctx context.Context, origin string, signer crypto.Signer, cfg ChainValidationConfig, cs storage.CreateStorage, httpDeadline time.Duration, maskInternalErrors bool) (http.Handler, error) {
cvOpts, err := newCertValidationOpts(cfg)
if err != nil {
return nil, fmt.Errorf("newCertValidationOpts(): %v", err)
}
log, err := scti.NewLog(ctx, origin, signer, *cvOpts, cs, sysTimeSource)
if err != nil {
return nil, fmt.Errorf("newLog(): %v", err)
}

opts := &HandlerOptions{
opts := &scti.HandlerOptions{
Deadline: httpDeadline,
RequestLog: &DefaultRequestLog{},
RequestLog: &scti.DefaultRequestLog{},
MaskInternalErrors: maskInternalErrors,
TimeSource: sysTimeSource,
}

handlers := NewPathHandlers(opts, log)
handlers := scti.NewPathHandlers(opts, log)
mux := http.NewServeMux()
// Register handlers for all the configured logs.
for path, handler := range handlers {
Expand Down
Loading
Loading