Follow new config practices and make cleaner
This commit is contained in:
parent
81ab482f6f
commit
2d9dbd0cfb
|
@ -6,9 +6,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
|
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
|
||||||
|
ct "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/google/certificate-transparency/go"
|
||||||
|
|
||||||
"github.com/letsencrypt/boulder/cmd"
|
"github.com/letsencrypt/boulder/cmd"
|
||||||
|
"github.com/letsencrypt/boulder/core"
|
||||||
blog "github.com/letsencrypt/boulder/log"
|
blog "github.com/letsencrypt/boulder/log"
|
||||||
"github.com/letsencrypt/boulder/publisher"
|
"github.com/letsencrypt/boulder/publisher"
|
||||||
"github.com/letsencrypt/boulder/rpc"
|
"github.com/letsencrypt/boulder/rpc"
|
||||||
|
@ -19,8 +24,26 @@ const clientName = "Publisher"
|
||||||
func main() {
|
func main() {
|
||||||
app := cmd.NewAppShell("boulder-publisher", "Submits issued certificates to CT logs")
|
app := cmd.NewAppShell("boulder-publisher", "Submits issued certificates to CT logs")
|
||||||
app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) {
|
app.Action = func(c cmd.Config, stats statsd.Statter, auditlogger *blog.AuditLogger) {
|
||||||
pubi, err := publisher.NewPublisherImpl(c.Common.CT)
|
logs := make([]*publisher.Log, len(c.Common.CT.Logs))
|
||||||
cmd.FailOnError(err, "Could not setup Publisher")
|
var err error
|
||||||
|
for i, ld := range c.Common.CT.Logs {
|
||||||
|
fmt.Println(ld)
|
||||||
|
logs[i], err = publisher.NewLog(ld.URI, ld.PublicKey)
|
||||||
|
cmd.FailOnError(err, "Unable to parse CT log description")
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Common.CT.IntermediateBundleFilename == "" {
|
||||||
|
auditlogger.Err("No CT submission bundle provided")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
pemBundle, err := core.LoadCertBundle(c.Common.CT.IntermediateBundleFilename)
|
||||||
|
cmd.FailOnError(err, "Failed to load CT submission bundle")
|
||||||
|
bundle := []ct.ASN1Cert{}
|
||||||
|
for _, cert := range pemBundle {
|
||||||
|
bundle = append(bundle, ct.ASN1Cert(cert.Raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
pubi := publisher.NewPublisherImpl(bundle, logs)
|
||||||
|
|
||||||
go cmd.DebugServer(c.Publisher.DebugAddr)
|
go cmd.DebugServer(c.Publisher.DebugAddr)
|
||||||
go cmd.ProfileCmd("Publisher", stats)
|
go cmd.ProfileCmd("Publisher", stats)
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
|
|
||||||
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
|
cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
|
||||||
"github.com/letsencrypt/boulder/core"
|
"github.com/letsencrypt/boulder/core"
|
||||||
"github.com/letsencrypt/boulder/publisher"
|
|
||||||
"github.com/letsencrypt/boulder/va"
|
"github.com/letsencrypt/boulder/va"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -160,7 +159,10 @@ type Config struct {
|
||||||
DNSTimeout string
|
DNSTimeout string
|
||||||
DNSAllowLoopbackAddresses bool
|
DNSAllowLoopbackAddresses bool
|
||||||
|
|
||||||
CT publisher.CTConfig
|
CT struct {
|
||||||
|
Logs []LogDescription
|
||||||
|
IntermediateBundleFilename string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CertChecker struct {
|
CertChecker struct {
|
||||||
|
@ -386,3 +388,9 @@ func (d *ConfigDuration) UnmarshalYAML(unmarshal func(interface{}) error) error
|
||||||
d.Duration = dur
|
d.Duration = dur
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogDescription something something
|
||||||
|
type LogDescription struct {
|
||||||
|
URI string `json:"uri"`
|
||||||
|
PublicKey string `json:"key"`
|
||||||
|
}
|
||||||
|
|
|
@ -6,14 +6,11 @@
|
||||||
package publisher
|
package publisher
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
ct "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/google/certificate-transparency/go"
|
ct "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/google/certificate-transparency/go"
|
||||||
ctClient "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/google/certificate-transparency/go/client"
|
ctClient "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/google/certificate-transparency/go/client"
|
||||||
|
@ -22,55 +19,38 @@ import (
|
||||||
blog "github.com/letsencrypt/boulder/log"
|
blog "github.com/letsencrypt/boulder/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogDescription tells you how to connect to a log and verify its statements.
|
// Log contains the CT client and signature verifier for a particular CT log
|
||||||
type LogDescription struct {
|
type Log struct {
|
||||||
Client *ctClient.LogClient
|
Client *ctClient.LogClient
|
||||||
Verifier *ct.SignatureVerifier
|
Verifier *ct.SignatureVerifier
|
||||||
}
|
}
|
||||||
|
|
||||||
type rawLogDescription struct {
|
// LogDescription something something
|
||||||
|
type LogDescription struct {
|
||||||
URI string `json:"uri"`
|
URI string `json:"uri"`
|
||||||
PublicKey string `json:"key"`
|
PublicKey string `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON parses a simple JSON format for log descriptions. Both the
|
// NewLog returns a initinalized Log struct
|
||||||
// URI and the public key are expected to be strings. The public key is a
|
func NewLog(uri, b64PK string) (*Log, error) {
|
||||||
// base64-encoded PKIX public key structure.
|
var l Log
|
||||||
func (logDesc *LogDescription) UnmarshalJSON(data []byte) error {
|
var err error
|
||||||
var rawLogDesc rawLogDescription
|
if strings.HasPrefix(uri, "/") {
|
||||||
err := json.Unmarshal(data, &rawLogDesc)
|
uri = uri[0 : len(uri)-2]
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Failed to unmarshal log description, %s", err)
|
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(rawLogDesc.URI, "/") {
|
l.Client = ctClient.New(uri)
|
||||||
rawLogDesc.URI = rawLogDesc.URI[0 : len(rawLogDesc.URI)-2]
|
|
||||||
}
|
|
||||||
logDesc.Client = ctClient.New(rawLogDesc.URI)
|
|
||||||
|
|
||||||
// Load Key
|
pkBytes, err := base64.StdEncoding.DecodeString(b64PK)
|
||||||
pkBytes, err := base64.StdEncoding.DecodeString(rawLogDesc.PublicKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to decode base64 log public key")
|
return nil, fmt.Errorf("Failed to decode base64 log public key")
|
||||||
}
|
}
|
||||||
pk, err := x509.ParsePKIXPublicKey(pkBytes)
|
pk, err := x509.ParsePKIXPublicKey(pkBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to parse log public key")
|
return nil, fmt.Errorf("Failed to parse log public key")
|
||||||
}
|
|
||||||
ecdsaKey, ok := pk.(*ecdsa.PublicKey)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("Failed to unmarshal log description for %s, unsupported public key type", rawLogDesc.URI)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logDesc.Verifier, err = ct.NewSignatureVerifier(ecdsaKey)
|
l.Verifier, err = ct.NewSignatureVerifier(pk)
|
||||||
return err
|
return &l, err
|
||||||
}
|
|
||||||
|
|
||||||
// CTConfig defines the JSON configuration file schema
|
|
||||||
type CTConfig struct {
|
|
||||||
Logs []LogDescription `json:"logs"`
|
|
||||||
SubmissionRetries int `json:"submissionRetries"`
|
|
||||||
SubmissionBackoffString string `json:"submissionBackoff"`
|
|
||||||
IntermediateBundleFilename string `json:"intermediateBundleFilename"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ctSubmissionRequest struct {
|
type ctSubmissionRequest struct {
|
||||||
|
@ -81,34 +61,21 @@ type ctSubmissionRequest struct {
|
||||||
type PublisherImpl struct {
|
type PublisherImpl struct {
|
||||||
log *blog.AuditLogger
|
log *blog.AuditLogger
|
||||||
client *http.Client
|
client *http.Client
|
||||||
submissionBackoff time.Duration
|
|
||||||
submissionRetries int
|
|
||||||
issuerBundle []ct.ASN1Cert
|
issuerBundle []ct.ASN1Cert
|
||||||
ctLogs []LogDescription
|
ctLogs []*Log
|
||||||
|
|
||||||
SA core.StorageAuthority
|
SA core.StorageAuthority
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublisherImpl creates a Publisher that will submit certificates
|
// NewPublisherImpl creates a Publisher that will submit certificates
|
||||||
// to any CT logs configured in CTConfig
|
// to any CT logs configured in CTConfig
|
||||||
func NewPublisherImpl(ctConfig CTConfig) (pub PublisherImpl, err error) {
|
func NewPublisherImpl(bundle []ct.ASN1Cert, logs []*Log) (pub PublisherImpl) {
|
||||||
logger := blog.GetAuditLogger()
|
logger := blog.GetAuditLogger()
|
||||||
logger.Notice("Publisher Authority Starting")
|
logger.Notice("Publisher Authority Starting")
|
||||||
|
|
||||||
if ctConfig.IntermediateBundleFilename == "" {
|
pub.issuerBundle = bundle
|
||||||
err = fmt.Errorf("No CT submission bundle provided")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
bundle, err := core.LoadCertBundle(ctConfig.IntermediateBundleFilename)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, cert := range bundle {
|
|
||||||
pub.issuerBundle = append(pub.issuerBundle, ct.ASN1Cert(cert.Raw))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub.log = logger
|
pub.log = logger
|
||||||
pub.ctLogs = ctConfig.Logs
|
pub.ctLogs = logs
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -256,8 +256,7 @@ func badLogSrv() *httptest.Server {
|
||||||
func setup(t *testing.T) (*PublisherImpl, *x509.Certificate, *ecdsa.PrivateKey) {
|
func setup(t *testing.T) (*PublisherImpl, *x509.Certificate, *ecdsa.PrivateKey) {
|
||||||
intermediatePEM, _ := pem.Decode([]byte(testIntermediate))
|
intermediatePEM, _ := pem.Decode([]byte(testIntermediate))
|
||||||
|
|
||||||
pub, err := NewPublisherImpl(CTConfig{IntermediateBundleFilename: issuerPath})
|
pub := NewPublisherImpl(nil, nil)
|
||||||
test.AssertNotError(t, err, "Couldn't create new Publisher")
|
|
||||||
pub.issuerBundle = append(pub.issuerBundle, ct.ASN1Cert(intermediatePEM.Bytes))
|
pub.issuerBundle = append(pub.issuerBundle, ct.ASN1Cert(intermediatePEM.Bytes))
|
||||||
pub.SA = mocks.NewStorageAuthority(clock.NewFake())
|
pub.SA = mocks.NewStorageAuthority(clock.NewFake())
|
||||||
|
|
||||||
|
@ -275,7 +274,7 @@ func addLog(t *testing.T, pub *PublisherImpl, port int, pubKey *ecdsa.PublicKey)
|
||||||
verifier, err := ct.NewSignatureVerifier(pubKey)
|
verifier, err := ct.NewSignatureVerifier(pubKey)
|
||||||
test.AssertNotError(t, err, "Couldn't create signature verifier")
|
test.AssertNotError(t, err, "Couldn't create signature verifier")
|
||||||
|
|
||||||
pub.ctLogs = append(pub.ctLogs, LogDescription{
|
pub.ctLogs = append(pub.ctLogs, &Log{
|
||||||
Client: ctClient.New(fmt.Sprintf("http://localhost:%d", port)),
|
Client: ctClient.New(fmt.Sprintf("http://localhost:%d", port)),
|
||||||
Verifier: verifier,
|
Verifier: verifier,
|
||||||
})
|
})
|
||||||
|
|
|
@ -288,8 +288,6 @@
|
||||||
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA=="
|
"key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA=="
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"submissionRetries": 1,
|
|
||||||
"submissionBackoff": "1s",
|
|
||||||
"intermediateBundleFilename": "test/test-ca.pem"
|
"intermediateBundleFilename": "test/test-ca.pem"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue