Merge branch 'master' into log-actual-ip

Conflicts:
	wfe/web-front-end_test.go
This commit is contained in:
Tom Clegg 2015-10-07 11:58:23 -07:00
commit f32c26c1de
23 changed files with 252 additions and 199 deletions

View File

@ -203,7 +203,7 @@ func TestRevoke(t *testing.T) {
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
csr, _ := x509.ParseCertificateRequest(CNandSANCSR) csr, _ := x509.ParseCertificateRequest(CNandSANCSR)
certObj, err := ca.IssueCertificate(*csr, ctx.reg.ID) certObj, err := ca.IssueCertificate(*csr, ctx.reg.ID)
@ -242,7 +242,7 @@ func TestIssueCertificate(t *testing.T) {
defer ctx.cleanUp() defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile) ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa
@ -319,7 +319,7 @@ func TestRejectNoName(t *testing.T) {
defer ctx.cleanUp() defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile) ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa
@ -336,7 +336,7 @@ func TestRejectTooManyNames(t *testing.T) {
defer ctx.cleanUp() defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile) ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa
@ -353,7 +353,7 @@ func TestDeduplication(t *testing.T) {
defer ctx.cleanUp() defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile) ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa
@ -377,7 +377,7 @@ func TestRejectValidityTooLong(t *testing.T) {
defer ctx.cleanUp() defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile) ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
test.AssertNotError(t, err, "Failed to create CA") test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa
@ -394,7 +394,7 @@ func TestShortKey(t *testing.T) {
ctx := setup(t) ctx := setup(t)
defer ctx.cleanUp() defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile) ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa
@ -410,7 +410,7 @@ func TestRejectBadAlgorithm(t *testing.T) {
ctx := setup(t) ctx := setup(t)
defer ctx.cleanUp() defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile) ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca.Publisher = &mocks.MockPublisher{} ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa ca.PA = ctx.pa
ca.SA = ctx.sa ca.SA = ctx.sa

View File

@ -130,6 +130,21 @@ func revokeByReg(regID int64, reasonCode core.RevocationCode, deny bool, rac rpc
return return
} }
// This abstraction is needed so that we can use sort.Sort below
type revocationCodes []core.RevocationCode
func (rc revocationCodes) Len() int {
return len(rc)
}
func (rc revocationCodes) Less(i, j int) bool {
return rc[i] < rc[j]
}
func (rc revocationCodes) Swap(i, j int) {
rc[i], rc[j] = rc[j], rc[i]
}
func main() { func main() {
app := cli.NewApp() app := cli.NewApp()
app.Name = "admin-revoker" app.Name = "admin-revoker"
@ -219,7 +234,7 @@ func main() {
Name: "list-reasons", Name: "list-reasons",
Usage: "List all revocation reason codes", Usage: "List all revocation reason codes",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
var codes core.RevocationCodes var codes revocationCodes
for k := range core.RevocationReasons { for k := range core.RevocationReasons {
codes = append(codes, k) codes = append(codes, k)
} }

View File

@ -145,7 +145,7 @@ func TestCheckCert(t *testing.T) {
} }
delete(problemsMap, p) delete(problemsMap, p)
} }
for k, _ := range problemsMap { for k := range problemsMap {
t.Errorf("Found unexpected problem '%s'.", k) t.Errorf("Found unexpected problem '%s'.", k)
} }

View File

@ -56,11 +56,11 @@ func (m *mockMail) SendMail(to []string, msg string) (err error) {
} }
type fakeRegStore struct { type fakeRegStore struct {
RegById map[int64]core.Registration RegByID map[int64]core.Registration
} }
func (f fakeRegStore) GetRegistration(id int64) (core.Registration, error) { func (f fakeRegStore) GetRegistration(id int64) (core.Registration, error) {
r, ok := f.RegById[id] r, ok := f.RegByID[id]
if !ok { if !ok {
msg := fmt.Sprintf("no such registration %d", id) msg := fmt.Sprintf("no such registration %d", id)
return r, core.NoSuchRegistrationError(msg) return r, core.NoSuchRegistrationError(msg)
@ -69,7 +69,7 @@ func (f fakeRegStore) GetRegistration(id int64) (core.Registration, error) {
} }
func newFakeRegStore() fakeRegStore { func newFakeRegStore() fakeRegStore {
return fakeRegStore{RegById: make(map[int64]core.Registration)} return fakeRegStore{RegByID: make(map[int64]core.Registration)}
} }
const testTmpl = `hi, cert for DNS names {{.DNSNames}} is going to expire in {{.DaysToExpiration}} days ({{.ExpirationDate}})` const testTmpl = `hi, cert for DNS names {{.DNSNames}} is going to expire in {{.DaysToExpiration}} days ({{.ExpirationDate}})`

View File

@ -30,7 +30,7 @@ import (
"log" "log"
"net" "net"
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof" // HTTP performance profiling, added transparently to HTTP APIs
"os" "os"
"runtime" "runtime"
"time" "time"
@ -219,6 +219,9 @@ type Config struct {
SubscriberAgreementURL string SubscriberAgreementURL string
} }
// CAConfig structs have configuration information for the certificate
// authority, including database parameters as well as controls for
// issued certificates.
type CAConfig struct { type CAConfig struct {
Profile string Profile string
TestMode bool TestMode bool
@ -241,6 +244,8 @@ type CAConfig struct {
DebugAddr string DebugAddr string
} }
// PAConfig specifies how a policy authority should connect to its
// database, and what policies it should enforce.
type PAConfig struct { type PAConfig struct {
DBConnect string DBConnect string
EnforcePolicyWhitelist bool EnforcePolicyWhitelist bool
@ -327,6 +332,7 @@ type AppShell struct {
App *cli.App App *cli.App
} }
// Version returns a string representing the version of boulder running.
func Version() string { func Version() string {
return fmt.Sprintf("0.1.0 [%s]", core.GetBuildID()) return fmt.Sprintf("0.1.0 [%s]", core.GetBuildID())
} }
@ -438,6 +444,11 @@ func LoadCert(path string) (cert []byte, err error) {
return return
} }
// DebugServer starts a server to receive debug information. Typical
// usage is to start it in a goroutine, configured with an address
// from the appropriate configuration object:
//
// go cmd.DebugServer(c.XA.DebugAddr)
func DebugServer(addr string) { func DebugServer(addr string) {
if addr == "" { if addr == "" {
log.Fatalf("unable to boot debug server because no address was given for it. Set debugAddr.") log.Fatalf("unable to boot debug server because no address was given for it. Set debugAddr.")
@ -450,12 +461,19 @@ func DebugServer(addr string) {
log.Println(http.Serve(ln, nil)) log.Println(http.Serve(ln, nil))
} }
// ConfigDuration is just an alias for time.Duration that allows
// serialization to YAML as well as JSON.
type ConfigDuration struct { type ConfigDuration struct {
time.Duration time.Duration
} }
// ErrDurationMustBeString is returned when a non-string value is
// presented to be deserialized as a ConfigDuration
var ErrDurationMustBeString = errors.New("cannot JSON unmarshal something other than a string into a ConfigDuration") var ErrDurationMustBeString = errors.New("cannot JSON unmarshal something other than a string into a ConfigDuration")
// UnmarshalJSON parses a string into a ConfigDuration using
// time.ParseDuration. If the input does not unmarshal as a
// string, then UnmarshalJSON returns ErrDurationMustBeString.
func (d *ConfigDuration) UnmarshalJSON(b []byte) error { func (d *ConfigDuration) UnmarshalJSON(b []byte) error {
s := "" s := ""
err := json.Unmarshal(b, &s) err := json.Unmarshal(b, &s)
@ -470,10 +488,13 @@ func (d *ConfigDuration) UnmarshalJSON(b []byte) error {
return err return err
} }
// MarshalJSON returns the string form of the duration, as a byte array.
func (d ConfigDuration) MarshalJSON() ([]byte, error) { func (d ConfigDuration) MarshalJSON() ([]byte, error) {
return []byte(d.Duration.String()), nil return []byte(d.Duration.String()), nil
} }
// UnmarshalYAML uses the same frmat as JSON, but is called by the YAML
// parser (vs. the JSON parser).
func (d *ConfigDuration) UnmarshalYAML(unmarshal func(interface{}) error) error { func (d *ConfigDuration) UnmarshalYAML(unmarshal func(interface{}) error) error {
var s string var s string
if err := unmarshal(&s); err != nil { if err := unmarshal(&s); err != nil {

View File

@ -38,7 +38,7 @@ func HTTPChallenge01(accountKey *jose.JsonWebKey) Challenge {
return newChallenge(ChallengeTypeHTTP01, accountKey) return newChallenge(ChallengeTypeHTTP01, accountKey)
} }
// DvsniChallenge01 constructs a random tls-sni-00 challenge // TLSSNIChallenge01 constructs a random tls-sni-00 challenge
func TLSSNIChallenge01(accountKey *jose.JsonWebKey) Challenge { func TLSSNIChallenge01(accountKey *jose.JsonWebKey) Challenge {
return newChallenge(ChallengeTypeTLSSNI01, accountKey) return newChallenge(ChallengeTypeTLSSNI01, accountKey)
} }

View File

@ -617,11 +617,6 @@ type Certificate struct {
Expires time.Time `db:"expires"` Expires time.Time `db:"expires"`
} }
type IssuedCertIdentifierData struct {
ReversedName string
Serial string
}
// IdentifierData holds information about what certificates are known for a // IdentifierData holds information about what certificates are known for a
// given identifier. This is used to present Proof of Posession challenges in // given identifier. This is used to present Proof of Posession challenges in
// the case where a certificate already exists. The DB table holding // the case where a certificate already exists. The DB table holding
@ -724,6 +719,8 @@ type OCSPSigningRequest struct {
RevokedAt time.Time RevokedAt time.Time
} }
// SignedCertificateTimestamp represents objects used by Certificate Transparency
// to demonstrate that a certificate was submitted to a CT log. See RFC 6962.
type SignedCertificateTimestamp struct { type SignedCertificateTimestamp struct {
ID int `db:"id"` ID int `db:"id"`
// The version of the protocol to which the SCT conforms // The version of the protocol to which the SCT conforms
@ -744,8 +741,6 @@ type SignedCertificateTimestamp struct {
LockCol int64 LockCol int64
} }
type RPCSignedCertificateTimestamp SignedCertificateTimestamp
type rawSignedCertificateTimestamp struct { type rawSignedCertificateTimestamp struct {
Version uint8 `json:"sct_version"` Version uint8 `json:"sct_version"`
LogID string `json:"id"` LogID string `json:"id"`
@ -754,6 +749,9 @@ type rawSignedCertificateTimestamp struct {
Extensions string `json:"extensions"` Extensions string `json:"extensions"`
} }
// UnmarshalJSON parses the add-chain response from a CT log. It fills all of
// the fields in the SignedCertificateTimestamp struct except for ID and
// CertificateSerial, which are used for local recordkeeping in the Boulder DB.
func (sct *SignedCertificateTimestamp) UnmarshalJSON(data []byte) error { func (sct *SignedCertificateTimestamp) UnmarshalJSON(data []byte) error {
var err error var err error
var rawSCT rawSignedCertificateTimestamp var rawSCT rawSignedCertificateTimestamp
@ -816,20 +814,6 @@ func (sct *SignedCertificateTimestamp) CheckSignature() error {
// RevocationCode is used to specify a certificate revocation reason // RevocationCode is used to specify a certificate revocation reason
type RevocationCode int type RevocationCode int
type RevocationCodes []RevocationCode
func (rc RevocationCodes) Len() int {
return len(rc)
}
func (rc RevocationCodes) Less(i, j int) bool {
return rc[i] < rc[j]
}
func (rc RevocationCodes) Swap(i, j int) {
rc[i], rc[j] = rc[j], rc[i]
}
// RevocationReasons provides a map from reason code to string explaining the // RevocationReasons provides a map from reason code to string explaining the
// code // code
var RevocationReasons = map[RevocationCode]string{ var RevocationReasons = map[RevocationCode]string{

View File

@ -301,6 +301,7 @@ func KeyDigestEquals(j, k crypto.PublicKey) bool {
// AcmeURL is a URL that automatically marshal/unmarshal to JSON strings // AcmeURL is a URL that automatically marshal/unmarshal to JSON strings
type AcmeURL url.URL type AcmeURL url.URL
// ParseAcmeURL is just a wrapper around url.Parse that returns an *AcmeURL
func ParseAcmeURL(s string) (*AcmeURL, error) { func ParseAcmeURL(s string) (*AcmeURL, error) {
u, err := url.Parse(s) u, err := url.Parse(s)
if err != nil { if err != nil {
@ -427,6 +428,9 @@ func StringToSerial(serial string) (*big.Int, error) {
return &serialNum, err return &serialNum, err
} }
// ValidSerial tests whether the input string represents a syntactically
// valid serial number, i.e., that it is a valid hex string between 32
// and 36 characters long.
func ValidSerial(serial string) bool { func ValidSerial(serial string) bool {
// Originally, serial numbers were 32 hex characters long. We later increased // Originally, serial numbers were 32 hex characters long. We later increased
// them to 36, but we allow the shorter ones because they exist in some // them to 36, but we allow the shorter ones because they exist in some

View File

@ -13,10 +13,10 @@ import (
blog "github.com/letsencrypt/boulder/log" blog "github.com/letsencrypt/boulder/log"
) )
// MockSyslogWriter implements the blog.SyslogWriter interface. It // SyslogWriter implements the blog.SyslogWriter interface. It
// stores all logged messages in a buffer for inspection by test // stores all logged messages in a buffer for inspection by test
// functions (via GetAll()) instead of sending them to syslog. // functions (via GetAll()) instead of sending them to syslog.
type MockSyslogWriter struct { type SyslogWriter struct {
logged []*LogMessage logged []*LogMessage
msgChan chan<- *LogMessage msgChan chan<- *LogMessage
getChan <-chan []*LogMessage getChan <-chan []*LogMessage
@ -24,7 +24,7 @@ type MockSyslogWriter struct {
closeChan chan<- struct{} closeChan chan<- struct{}
} }
// LogMessage is a log entry that has been sent to a MockSyslogWriter. // LogMessage is a log entry that has been sent to a SyslogWriter.
type LogMessage struct { type LogMessage struct {
Priority syslog.Priority // aka Log level Priority syslog.Priority // aka Log level
Message string // content of log message Message string // content of log message
@ -54,19 +54,19 @@ func (lm *LogMessage) String() string {
// // ... // // ...
// Assert(t, len(log.GetAll()) > 0, "Should have logged something") // Assert(t, len(log.GetAll()) > 0, "Should have logged something")
// } // }
func UseMockLog() *MockSyslogWriter { func UseMockLog() *SyslogWriter {
sw := NewSyslogWriter() sw := NewSyslogWriter()
blog.GetAuditLogger().SyslogWriter = sw blog.GetAuditLogger().SyslogWriter = sw
return sw return sw
} }
// NewSyslogWriter returns a new MockSyslogWriter. // NewSyslogWriter returns a new SyslogWriter.
func NewSyslogWriter() *MockSyslogWriter { func NewSyslogWriter() *SyslogWriter {
msgChan := make(chan *LogMessage) msgChan := make(chan *LogMessage)
getChan := make(chan []*LogMessage) getChan := make(chan []*LogMessage)
clearChan := make(chan struct{}) clearChan := make(chan struct{})
closeChan := make(chan struct{}) closeChan := make(chan struct{})
msw := &MockSyslogWriter{ msw := &SyslogWriter{
logged: []*LogMessage{}, logged: []*LogMessage{},
msgChan: msgChan, msgChan: msgChan,
getChan: getChan, getChan: getChan,
@ -91,7 +91,7 @@ func NewSyslogWriter() *MockSyslogWriter {
return msw return msw
} }
func (msw *MockSyslogWriter) write(m string, priority syslog.Priority) error { func (msw *SyslogWriter) write(m string, priority syslog.Priority) error {
msw.msgChan <- &LogMessage{Message: m, Priority: priority} msw.msgChan <- &LogMessage{Message: m, Priority: priority}
return nil return nil
} }
@ -100,7 +100,7 @@ func (msw *MockSyslogWriter) write(m string, priority syslog.Priority) error {
// Clear(), if applicable). // Clear(), if applicable).
// //
// The caller must not modify the returned slice or its elements. // The caller must not modify the returned slice or its elements.
func (msw *MockSyslogWriter) GetAll() []*LogMessage { func (msw *SyslogWriter) GetAll() []*LogMessage {
return <-msw.getChan return <-msw.getChan
} }
@ -110,7 +110,7 @@ func (msw *MockSyslogWriter) GetAll() []*LogMessage {
// is more important than performance. // is more important than performance.
// //
// The caller must not modify the elements of the returned slice. // The caller must not modify the elements of the returned slice.
func (msw *MockSyslogWriter) GetAllMatching(reString string) (matches []*LogMessage) { func (msw *SyslogWriter) GetAllMatching(reString string) (matches []*LogMessage) {
re := regexp.MustCompile(reString) re := regexp.MustCompile(reString)
for _, logMsg := range <-msw.getChan { for _, logMsg := range <-msw.getChan {
if re.MatchString(logMsg.Message) { if re.MatchString(logMsg.Message) {
@ -121,52 +121,52 @@ func (msw *MockSyslogWriter) GetAllMatching(reString string) (matches []*LogMess
} }
// Clear resets the log buffer. // Clear resets the log buffer.
func (msw *MockSyslogWriter) Clear() { func (msw *SyslogWriter) Clear() {
msw.clearChan <- struct{}{} msw.clearChan <- struct{}{}
} }
// Close releases resources. No other methods may be called after this. // Close releases resources. No other methods may be called after this.
func (msw *MockSyslogWriter) Close() error { func (msw *SyslogWriter) Close() error {
msw.closeChan <- struct{}{} msw.closeChan <- struct{}{}
return nil return nil
} }
// Alert logs at LOG_ALERT // Alert logs at LOG_ALERT
func (msw *MockSyslogWriter) Alert(m string) error { func (msw *SyslogWriter) Alert(m string) error {
return msw.write(m, syslog.LOG_ALERT) return msw.write(m, syslog.LOG_ALERT)
} }
// Crit logs at LOG_CRIT // Crit logs at LOG_CRIT
func (msw *MockSyslogWriter) Crit(m string) error { func (msw *SyslogWriter) Crit(m string) error {
return msw.write(m, syslog.LOG_CRIT) return msw.write(m, syslog.LOG_CRIT)
} }
// Debug logs at LOG_DEBUG // Debug logs at LOG_DEBUG
func (msw *MockSyslogWriter) Debug(m string) error { func (msw *SyslogWriter) Debug(m string) error {
return msw.write(m, syslog.LOG_DEBUG) return msw.write(m, syslog.LOG_DEBUG)
} }
// Emerg logs at LOG_EMERG // Emerg logs at LOG_EMERG
func (msw *MockSyslogWriter) Emerg(m string) error { func (msw *SyslogWriter) Emerg(m string) error {
return msw.write(m, syslog.LOG_EMERG) return msw.write(m, syslog.LOG_EMERG)
} }
// Err logs at LOG_ERR // Err logs at LOG_ERR
func (msw *MockSyslogWriter) Err(m string) error { func (msw *SyslogWriter) Err(m string) error {
return msw.write(m, syslog.LOG_ERR) return msw.write(m, syslog.LOG_ERR)
} }
// Info logs at LOG_INFO // Info logs at LOG_INFO
func (msw *MockSyslogWriter) Info(m string) error { func (msw *SyslogWriter) Info(m string) error {
return msw.write(m, syslog.LOG_INFO) return msw.write(m, syslog.LOG_INFO)
} }
// Notice logs at LOG_NOTICE // Notice logs at LOG_NOTICE
func (msw *MockSyslogWriter) Notice(m string) error { func (msw *SyslogWriter) Notice(m string) error {
return msw.write(m, syslog.LOG_NOTICE) return msw.write(m, syslog.LOG_NOTICE)
} }
// Warning logs at LOG_WARNING // Warning logs at LOG_WARNING
func (msw *MockSyslogWriter) Warning(m string) error { func (msw *SyslogWriter) Warning(m string) error {
return msw.write(m, syslog.LOG_WARNING) return msw.write(m, syslog.LOG_WARNING)
} }

View File

@ -20,17 +20,17 @@ import (
"github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/core"
) )
// MockDNS is a mock // DNSResolver is a mock
type MockDNS struct { type DNSResolver struct {
} }
// ExchangeOne is a mock // ExchangeOne is a mock
func (mock *MockDNS) ExchangeOne(hostname string, qt uint16) (rsp *dns.Msg, rtt time.Duration, err error) { func (mock *DNSResolver) ExchangeOne(hostname string, qt uint16) (rsp *dns.Msg, rtt time.Duration, err error) {
return nil, 0, nil return nil, 0, nil
} }
// LookupTXT is a mock // LookupTXT is a mock
func (mock *MockDNS) LookupTXT(hostname string) ([]string, time.Duration, error) { func (mock *DNSResolver) LookupTXT(hostname string) ([]string, time.Duration, error) {
if hostname == "_acme-challenge.servfail.com" { if hostname == "_acme-challenge.servfail.com" {
return nil, 0, fmt.Errorf("SERVFAIL") return nil, 0, fmt.Errorf("SERVFAIL")
} }
@ -38,7 +38,7 @@ func (mock *MockDNS) LookupTXT(hostname string) ([]string, time.Duration, error)
} }
// LookupHost is a mock // LookupHost is a mock
func (mock *MockDNS) LookupHost(hostname string) ([]net.IP, time.Duration, error) { func (mock *DNSResolver) LookupHost(hostname string) ([]net.IP, time.Duration, error) {
if hostname == "always.invalid" || hostname == "invalid.invalid" { if hostname == "always.invalid" || hostname == "invalid.invalid" {
return []net.IP{}, 0, nil return []net.IP{}, 0, nil
} }
@ -47,7 +47,7 @@ func (mock *MockDNS) LookupHost(hostname string) ([]net.IP, time.Duration, error
} }
// LookupCNAME is a mock // LookupCNAME is a mock
func (mock *MockDNS) LookupCNAME(domain string) (string, time.Duration, error) { func (mock *DNSResolver) LookupCNAME(domain string) (string, time.Duration, error) {
switch strings.TrimRight(domain, ".") { switch strings.TrimRight(domain, ".") {
case "cname-absent.com": case "cname-absent.com":
return "absent.com.", 30, nil return "absent.com.", 30, nil
@ -76,7 +76,7 @@ func (mock *MockDNS) LookupCNAME(domain string) (string, time.Duration, error) {
} }
// LookupDNAME is a mock // LookupDNAME is a mock
func (mock *MockDNS) LookupDNAME(domain string) (string, time.Duration, error) { func (mock *DNSResolver) LookupDNAME(domain string) (string, time.Duration, error) {
switch strings.TrimRight(domain, ".") { switch strings.TrimRight(domain, ".") {
case "cname-and-dname.com", "dname-present.com": case "cname-and-dname.com", "dname-present.com":
return "dname-target.present.com.", time.Minute, nil return "dname-target.present.com.", time.Minute, nil
@ -94,7 +94,7 @@ func (mock *MockDNS) LookupDNAME(domain string) (string, time.Duration, error) {
} }
// LookupCAA is a mock // LookupCAA is a mock
func (mock *MockDNS) LookupCAA(domain string) ([]*dns.CAA, time.Duration, error) { func (mock *DNSResolver) LookupCAA(domain string) ([]*dns.CAA, time.Duration, error) {
var results []*dns.CAA var results []*dns.CAA
var record dns.CAA var record dns.CAA
switch strings.TrimRight(domain, ".") { switch strings.TrimRight(domain, ".") {
@ -118,7 +118,7 @@ func (mock *MockDNS) LookupCAA(domain string) ([]*dns.CAA, time.Duration, error)
} }
// LookupMX is a mock // LookupMX is a mock
func (mock *MockDNS) LookupMX(domain string) ([]string, time.Duration, error) { func (mock *DNSResolver) LookupMX(domain string) ([]string, time.Duration, error) {
switch strings.TrimRight(domain, ".") { switch strings.TrimRight(domain, ".") {
case "letsencrypt.org": case "letsencrypt.org":
fallthrough fallthrough
@ -128,8 +128,8 @@ func (mock *MockDNS) LookupMX(domain string) ([]string, time.Duration, error) {
return nil, 0, nil return nil, 0, nil
} }
// MockSA is a mock // StorageAuthority is a mock
type MockSA struct { type StorageAuthority struct {
authorizedDomains map[string]bool authorizedDomains map[string]bool
} }
@ -149,7 +149,7 @@ const (
) )
// GetRegistration is a mock // GetRegistration is a mock
func (sa *MockSA) GetRegistration(id int64) (core.Registration, error) { func (sa *StorageAuthority) GetRegistration(id int64) (core.Registration, error) {
if id == 100 { if id == 100 {
// Tag meaning "Missing" // Tag meaning "Missing"
return core.Registration{}, errors.New("missing") return core.Registration{}, errors.New("missing")
@ -167,7 +167,7 @@ func (sa *MockSA) GetRegistration(id int64) (core.Registration, error) {
} }
// GetRegistrationByKey is a mock // GetRegistrationByKey is a mock
func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) { func (sa *StorageAuthority) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) {
var test1KeyPublic jose.JsonWebKey var test1KeyPublic jose.JsonWebKey
var test2KeyPublic jose.JsonWebKey var test2KeyPublic jose.JsonWebKey
test1KeyPublic.UnmarshalJSON([]byte(test1KeyPublicJSON)) test1KeyPublic.UnmarshalJSON([]byte(test1KeyPublicJSON))
@ -187,7 +187,7 @@ func (sa *MockSA) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration,
} }
// GetAuthorization is a mock // GetAuthorization is a mock
func (sa *MockSA) GetAuthorization(id string) (core.Authorization, error) { func (sa *StorageAuthority) GetAuthorization(id string) (core.Authorization, error) {
if id == "valid" { if id == "valid" {
exp := time.Now().AddDate(100, 0, 0) exp := time.Now().AddDate(100, 0, 0)
return core.Authorization{ return core.Authorization{
@ -209,7 +209,7 @@ func (sa *MockSA) GetAuthorization(id string) (core.Authorization, error) {
} }
// GetCertificate is a mock // GetCertificate is a mock
func (sa *MockSA) GetCertificate(serial string) (core.Certificate, error) { func (sa *StorageAuthority) GetCertificate(serial string) (core.Certificate, error) {
// Serial ee == 238.crt // Serial ee == 238.crt
if serial == "0000000000000000000000000000000000ee" { if serial == "0000000000000000000000000000000000ee" {
certPemBytes, _ := ioutil.ReadFile("test/238.crt") certPemBytes, _ := ioutil.ReadFile("test/238.crt")
@ -231,7 +231,7 @@ func (sa *MockSA) GetCertificate(serial string) (core.Certificate, error) {
} }
// GetCertificateStatus is a mock // GetCertificateStatus is a mock
func (sa *MockSA) GetCertificateStatus(serial string) (core.CertificateStatus, error) { func (sa *StorageAuthority) GetCertificateStatus(serial string) (core.CertificateStatus, error) {
// Serial ee == 238.crt // Serial ee == 238.crt
if serial == "0000000000000000000000000000000000ee" { if serial == "0000000000000000000000000000000000ee" {
return core.CertificateStatus{ return core.CertificateStatus{
@ -247,57 +247,57 @@ func (sa *MockSA) GetCertificateStatus(serial string) (core.CertificateStatus, e
} }
// AlreadyDeniedCSR is a mock // AlreadyDeniedCSR is a mock
func (sa *MockSA) AlreadyDeniedCSR([]string) (bool, error) { func (sa *StorageAuthority) AlreadyDeniedCSR([]string) (bool, error) {
return false, nil return false, nil
} }
// AddCertificate is a mock // AddCertificate is a mock
func (sa *MockSA) AddCertificate(certDER []byte, regID int64) (digest string, err error) { func (sa *StorageAuthority) AddCertificate(certDER []byte, regID int64) (digest string, err error) {
return return
} }
// FinalizeAuthorization is a mock // FinalizeAuthorization is a mock
func (sa *MockSA) FinalizeAuthorization(authz core.Authorization) (err error) { func (sa *StorageAuthority) FinalizeAuthorization(authz core.Authorization) (err error) {
return return
} }
// MarkCertificateRevoked is a mock // MarkCertificateRevoked is a mock
func (sa *MockSA) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode core.RevocationCode) (err error) { func (sa *StorageAuthority) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode core.RevocationCode) (err error) {
return return
} }
// UpdateOCSP is a mock // UpdateOCSP is a mock
func (sa *MockSA) UpdateOCSP(serial string, ocspResponse []byte) (err error) { func (sa *StorageAuthority) UpdateOCSP(serial string, ocspResponse []byte) (err error) {
return return
} }
// NewPendingAuthorization is a mock // NewPendingAuthorization is a mock
func (sa *MockSA) NewPendingAuthorization(authz core.Authorization) (output core.Authorization, err error) { func (sa *StorageAuthority) NewPendingAuthorization(authz core.Authorization) (output core.Authorization, err error) {
return return
} }
// NewRegistration is a mock // NewRegistration is a mock
func (sa *MockSA) NewRegistration(reg core.Registration) (regR core.Registration, err error) { func (sa *StorageAuthority) NewRegistration(reg core.Registration) (regR core.Registration, err error) {
return return
} }
// UpdatePendingAuthorization is a mock // UpdatePendingAuthorization is a mock
func (sa *MockSA) UpdatePendingAuthorization(authz core.Authorization) (err error) { func (sa *StorageAuthority) UpdatePendingAuthorization(authz core.Authorization) (err error) {
return return
} }
// UpdateRegistration is a mock // UpdateRegistration is a mock
func (sa *MockSA) UpdateRegistration(reg core.Registration) (err error) { func (sa *StorageAuthority) UpdateRegistration(reg core.Registration) (err error) {
return return
} }
// GetSCTReceipt is a mock // GetSCTReceipt is a mock
func (sa *MockSA) GetSCTReceipt(serial string, logID string) (sct core.SignedCertificateTimestamp, err error) { func (sa *StorageAuthority) GetSCTReceipt(serial string, logID string) (sct core.SignedCertificateTimestamp, err error) {
return return
} }
// AddSCTReceipt is a mock // AddSCTReceipt is a mock
func (sa *MockSA) AddSCTReceipt(sct core.SignedCertificateTimestamp) (err error) { func (sa *StorageAuthority) AddSCTReceipt(sct core.SignedCertificateTimestamp) (err error) {
if sct.Signature == nil { if sct.Signature == nil {
err = fmt.Errorf("Bad times") err = fmt.Errorf("Bad times")
} }
@ -305,8 +305,8 @@ func (sa *MockSA) AddSCTReceipt(sct core.SignedCertificateTimestamp) (err error)
} }
// GetLatestValidAuthorization is a mock // GetLatestValidAuthorization is a mock
func (sa *MockSA) GetLatestValidAuthorization(registrationId int64, identifier core.AcmeIdentifier) (authz core.Authorization, err error) { func (sa *StorageAuthority) GetLatestValidAuthorization(registrationID int64, identifier core.AcmeIdentifier) (authz core.Authorization, err error) {
if registrationId == 1 && identifier.Type == "dns" { if registrationID == 1 && identifier.Type == "dns" {
if sa.authorizedDomains[identifier.Value] || identifier.Value == "not-an-example.com" { if sa.authorizedDomains[identifier.Value] || identifier.Value == "not-an-example.com" {
exp := time.Now().AddDate(100, 0, 0) exp := time.Now().AddDate(100, 0, 0)
return core.Authorization{Status: core.StatusValid, RegistrationID: 1, Expires: &exp, Identifier: identifier}, nil return core.Authorization{Status: core.StatusValid, RegistrationID: 1, Expires: &exp, Identifier: identifier}, nil
@ -316,16 +316,16 @@ func (sa *MockSA) GetLatestValidAuthorization(registrationId int64, identifier c
} }
// CountCertificatesRange is a mock // CountCertificatesRange is a mock
func (sa *MockSA) CountCertificatesRange(_, _ time.Time) (int64, error) { func (sa *StorageAuthority) CountCertificatesRange(_, _ time.Time) (int64, error) {
return 0, nil return 0, nil
} }
// MockPublisher is a mock // Publisher is a mock
type MockPublisher struct { type Publisher struct {
// empty // empty
} }
// SubmitToCT is a mock // SubmitToCT is a mock
func (*MockPublisher) SubmitToCT([]byte) error { func (*Publisher) SubmitToCT([]byte) error {
return nil return nil
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/letsencrypt/boulder/sa" "github.com/letsencrypt/boulder/sa"
) )
// LogDescription tells you how to connect to a log and verify its statements.
type LogDescription struct { type LogDescription struct {
ID string ID string
URI string URI string
@ -35,6 +36,9 @@ type rawLogDescription struct {
PublicKey string `json:"key"` PublicKey string `json:"key"`
} }
// UnmarshalJSON parses a simple JSON format for log descriptions. Both the
// URI and the public key are expected to be strings. The public key is a
// base64-encoded PKIX public key structure.
func (logDesc *LogDescription) UnmarshalJSON(data []byte) error { func (logDesc *LogDescription) UnmarshalJSON(data []byte) error {
var rawLogDesc rawLogDescription var rawLogDesc rawLogDescription
if err := json.Unmarshal(data, &rawLogDesc); err != nil { if err := json.Unmarshal(data, &rawLogDesc); err != nil {

View File

@ -196,7 +196,7 @@ func setup(t *testing.T, port, retries int) (PublisherImpl, *x509.Certificate) {
}) })
test.AssertNotError(t, err, "Couldn't create new Publisher") test.AssertNotError(t, err, "Couldn't create new Publisher")
pub.issuerBundle = append(pub.issuerBundle, base64.StdEncoding.EncodeToString(intermediatePEM.Bytes)) pub.issuerBundle = append(pub.issuerBundle, base64.StdEncoding.EncodeToString(intermediatePEM.Bytes))
pub.SA = &mocks.MockSA{} pub.SA = &mocks.StorageAuthority{}
leafPEM, _ := pem.Decode([]byte(testLeaf)) leafPEM, _ := pem.Decode([]byte(testLeaf))
leaf, err := x509.ParseCertificate(leafPEM.Bytes) leaf, err := x509.ParseCertificate(leafPEM.Bytes)

View File

@ -202,7 +202,7 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
ValidityPeriod: time.Hour * 2190, ValidityPeriod: time.Hour * 2190,
NotAfter: time.Now().Add(time.Hour * 8761), NotAfter: time.Now().Add(time.Hour * 8761),
Clk: fc, Clk: fc,
Publisher: &mocks.MockPublisher{}, Publisher: &mocks.Publisher{},
} }
cleanUp := func() { cleanUp := func() {
saDBCleanUp() saDBCleanUp()
@ -225,7 +225,7 @@ func initAuthorities(t *testing.T) (*DummyValidationAuthority, *sa.SQLStorageAut
ra.VA = va ra.VA = va
ra.CA = &ca ra.CA = &ca
ra.PA = pa ra.PA = pa
ra.DNSResolver = &mocks.MockDNS{} ra.DNSResolver = &mocks.DNSResolver{}
AuthzInitial.RegistrationID = Registration.ID AuthzInitial.RegistrationID = Registration.ID
@ -263,38 +263,38 @@ func TestValidateContacts(t *testing.T) {
nStats, _ := statsd.NewNoopClient() nStats, _ := statsd.NewNoopClient()
err := validateContacts([]*core.AcmeURL{}, &mocks.MockDNS{}, nStats) err := validateContacts([]*core.AcmeURL{}, &mocks.DNSResolver{}, nStats)
test.AssertNotError(t, err, "No Contacts") test.AssertNotError(t, err, "No Contacts")
err = validateContacts([]*core.AcmeURL{tel}, &mocks.MockDNS{}, nStats) err = validateContacts([]*core.AcmeURL{tel}, &mocks.DNSResolver{}, nStats)
test.AssertNotError(t, err, "Simple Telephone") test.AssertNotError(t, err, "Simple Telephone")
err = validateContacts([]*core.AcmeURL{validEmail}, &mocks.MockDNS{}, nStats) err = validateContacts([]*core.AcmeURL{validEmail}, &mocks.DNSResolver{}, nStats)
test.AssertNotError(t, err, "Valid Email") test.AssertNotError(t, err, "Valid Email")
err = validateContacts([]*core.AcmeURL{invalidEmail}, &mocks.MockDNS{}, nStats) err = validateContacts([]*core.AcmeURL{invalidEmail}, &mocks.DNSResolver{}, nStats)
test.AssertError(t, err, "Invalid Email") test.AssertError(t, err, "Invalid Email")
err = validateContacts([]*core.AcmeURL{malformedEmail}, &mocks.MockDNS{}, nStats) err = validateContacts([]*core.AcmeURL{malformedEmail}, &mocks.DNSResolver{}, nStats)
test.AssertError(t, err, "Malformed Email") test.AssertError(t, err, "Malformed Email")
err = validateContacts([]*core.AcmeURL{ansible}, &mocks.MockDNS{}, nStats) err = validateContacts([]*core.AcmeURL{ansible}, &mocks.DNSResolver{}, nStats)
test.AssertError(t, err, "Unknown scehme") test.AssertError(t, err, "Unknown scehme")
} }
func TestValidateEmail(t *testing.T) { func TestValidateEmail(t *testing.T) {
_, err := validateEmail("an email`", &mocks.MockDNS{}) _, err := validateEmail("an email`", &mocks.DNSResolver{})
test.AssertError(t, err, "Malformed") test.AssertError(t, err, "Malformed")
_, err = validateEmail("a@not.a.domain", &mocks.MockDNS{}) _, err = validateEmail("a@not.a.domain", &mocks.DNSResolver{})
test.AssertError(t, err, "Cannot resolve") test.AssertError(t, err, "Cannot resolve")
t.Logf("No Resolve: %s", err) t.Logf("No Resolve: %s", err)
_, err = validateEmail("a@example.com", &mocks.MockDNS{}) _, err = validateEmail("a@example.com", &mocks.DNSResolver{})
test.AssertError(t, err, "No MX Record") test.AssertError(t, err, "No MX Record")
t.Logf("No MX: %s", err) t.Logf("No MX: %s", err)
_, err = validateEmail("a@email.com", &mocks.MockDNS{}) _, err = validateEmail("a@email.com", &mocks.DNSResolver{})
test.AssertNotError(t, err, "Valid") test.AssertNotError(t, err, "Valid")
} }

View File

@ -200,16 +200,16 @@ func (rpc *AmqpRPCServer) Handle(method string, handler func([]byte) ([]byte, er
rpc.dispatchTable[method] = handler rpc.dispatchTable[method] = handler
} }
// RPCError is a JSON wrapper for error as it cannot be un/marshalled // rpcError is a JSON wrapper for error as it cannot be un/marshalled
// due to type interface{}. // due to type interface{}.
type RPCError struct { type rpcError struct {
Value string `json:"value"` Value string `json:"value"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
} }
// Wraps a error in a RPCError so it can be marshalled to // Wraps a error in a rpcError so it can be marshalled to
// JSON. // JSON.
func wrapError(err error) (rpcError RPCError) { func wrapError(err error) (rpcError rpcError) {
if err != nil { if err != nil {
rpcError.Value = err.Error() rpcError.Value = err.Error()
switch err.(type) { switch err.(type) {
@ -240,8 +240,8 @@ func wrapError(err error) (rpcError RPCError) {
return return
} }
// Unwraps a RPCError and returns the correct error type. // Unwraps a rpcError and returns the correct error type.
func unwrapError(rpcError RPCError) (err error) { func unwrapError(rpcError rpcError) (err error) {
if rpcError.Value != "" { if rpcError.Value != "" {
switch rpcError.Type { switch rpcError.Type {
case "InternalServerError": case "InternalServerError":
@ -273,11 +273,11 @@ func unwrapError(rpcError RPCError) (err error) {
return return
} }
// RPCResponse is a stuct for wire-representation of response messages // rpcResponse is a stuct for wire-representation of response messages
// used by DispatchSync // used by DispatchSync
type RPCResponse struct { type rpcResponse struct {
ReturnVal []byte `json:"returnVal,omitempty"` ReturnVal []byte `json:"returnVal,omitempty"`
Error RPCError `json:"error,omitempty"` Error rpcError `json:"error,omitempty"`
} }
// AmqpChannel sets a AMQP connection up using SSL if configuration is provided // AmqpChannel sets a AMQP connection up using SSL if configuration is provided
@ -362,7 +362,7 @@ func (rpc *AmqpRPCServer) processMessage(msg amqp.Delivery) {
rpc.log.Audit(fmt.Sprintf(" [s<][%s][%s] Misrouted message: %s - %s - %s", rpc.serverQueue, msg.ReplyTo, msg.Type, core.B64enc(msg.Body), msg.CorrelationId)) rpc.log.Audit(fmt.Sprintf(" [s<][%s][%s] Misrouted message: %s - %s - %s", rpc.serverQueue, msg.ReplyTo, msg.Type, core.B64enc(msg.Body), msg.CorrelationId))
return return
} }
var response RPCResponse var response rpcResponse
var err error var err error
response.ReturnVal, err = cb(msg.Body) response.ReturnVal, err = cb(msg.Body)
response.Error = wrapError(err) response.Error = wrapError(err)
@ -407,7 +407,7 @@ func (rpc *AmqpRPCServer) replyTooManyRequests(msg amqp.Delivery) {
// until a fatal error is returned or AmqpRPCServer.Stop() is called and all // until a fatal error is returned or AmqpRPCServer.Stop() is called and all
// remaining messages are processed. // remaining messages are processed.
func (rpc *AmqpRPCServer) Start(c cmd.Config) error { func (rpc *AmqpRPCServer) Start(c cmd.Config) error {
tooManyGoroutines := RPCResponse{ tooManyGoroutines := rpcResponse{
Error: wrapError(core.TooManyRPCRequestsError("RPC server has spawned too many Goroutines")), Error: wrapError(core.TooManyRPCRequestsError("RPC server has spawned too many Goroutines")),
} }
tooManyRequestsResponse, err := json.Marshal(tooManyGoroutines) tooManyRequestsResponse, err := json.Marshal(tooManyGoroutines)
@ -632,7 +632,7 @@ func (rpc *AmqpRPCCLient) DispatchSync(method string, body []byte) (response []b
callStarted := time.Now() callStarted := time.Now()
select { select {
case jsonResponse := <-rpc.Dispatch(method, body): case jsonResponse := <-rpc.Dispatch(method, body):
var rpcResponse RPCResponse var rpcResponse rpcResponse
err = json.Unmarshal(jsonResponse, &rpcResponse) err = json.Unmarshal(jsonResponse, &rpcResponse)
if err != nil { if err != nil {
return return

View File

@ -9,14 +9,14 @@ import (
"time" "time"
) )
// RPCClient describes the functions an RPC Client performs // Client describes the functions an RPC Client performs
type RPCClient interface { type Client interface {
SetTimeout(time.Duration) SetTimeout(time.Duration)
Dispatch(string, []byte) chan []byte Dispatch(string, []byte) chan []byte
DispatchSync(string, []byte) ([]byte, error) DispatchSync(string, []byte) ([]byte, error)
} }
// RPCServer describes the functions an RPC Server performs // Server describes the functions an RPC Server performs
type RPCServer interface { type Server interface {
Handle(string, func([]byte) ([]byte, error)) Handle(string, func([]byte) ([]byte, error))
} }

View File

@ -161,7 +161,7 @@ func errorCondition(method string, err error, obj interface{}) {
} }
// NewRegistrationAuthorityServer constructs an RPC server // NewRegistrationAuthorityServer constructs an RPC server
func NewRegistrationAuthorityServer(rpc RPCServer, impl core.RegistrationAuthority) error { func NewRegistrationAuthorityServer(rpc Server, impl core.RegistrationAuthority) error {
log := blog.GetAuditLogger() log := blog.GetAuditLogger()
rpc.Handle(MethodNewRegistration, func(req []byte) (response []byte, err error) { rpc.Handle(MethodNewRegistration, func(req []byte) (response []byte, err error) {
@ -338,11 +338,11 @@ func NewRegistrationAuthorityServer(rpc RPCServer, impl core.RegistrationAuthori
// RegistrationAuthorityClient represents an RA RPC client // RegistrationAuthorityClient represents an RA RPC client
type RegistrationAuthorityClient struct { type RegistrationAuthorityClient struct {
rpc RPCClient rpc Client
} }
// NewRegistrationAuthorityClient constructs an RPC client // NewRegistrationAuthorityClient constructs an RPC client
func NewRegistrationAuthorityClient(client RPCClient) (rac RegistrationAuthorityClient, err error) { func NewRegistrationAuthorityClient(client Client) (rac RegistrationAuthorityClient, err error) {
rac = RegistrationAuthorityClient{rpc: client} rac = RegistrationAuthorityClient{rpc: client}
return return
} }
@ -489,7 +489,7 @@ func (rac RegistrationAuthorityClient) OnValidationUpdate(authz core.Authorizati
// //
// ValidationAuthorityClient / Server // ValidationAuthorityClient / Server
// -> UpdateValidations // -> UpdateValidations
func NewValidationAuthorityServer(rpc RPCServer, impl core.ValidationAuthority) (err error) { func NewValidationAuthorityServer(rpc Server, impl core.ValidationAuthority) (err error) {
rpc.Handle(MethodUpdateValidations, func(req []byte) (response []byte, err error) { rpc.Handle(MethodUpdateValidations, func(req []byte) (response []byte, err error) {
var vaReq validationRequest var vaReq validationRequest
if err = json.Unmarshal(req, &vaReq); err != nil { if err = json.Unmarshal(req, &vaReq); err != nil {
@ -533,11 +533,11 @@ func NewValidationAuthorityServer(rpc RPCServer, impl core.ValidationAuthority)
// ValidationAuthorityClient represents an RPC client for the VA // ValidationAuthorityClient represents an RPC client for the VA
type ValidationAuthorityClient struct { type ValidationAuthorityClient struct {
rpc RPCClient rpc Client
} }
// NewValidationAuthorityClient constructs an RPC client // NewValidationAuthorityClient constructs an RPC client
func NewValidationAuthorityClient(client RPCClient) (vac ValidationAuthorityClient, err error) { func NewValidationAuthorityClient(client Client) (vac ValidationAuthorityClient, err error) {
vac = ValidationAuthorityClient{rpc: client} vac = ValidationAuthorityClient{rpc: client}
return return
} }
@ -582,7 +582,8 @@ func (vac ValidationAuthorityClient) CheckCAARecords(ident core.AcmeIdentifier)
return return
} }
func NewPublisherServer(rpc RPCServer, impl core.Publisher) (err error) { // NewPublisherServer creates a new server that wraps a CT publisher
func NewPublisherServer(rpc Server, impl core.Publisher) (err error) {
rpc.Handle(MethodSubmitToCT, func(req []byte) (response []byte, err error) { rpc.Handle(MethodSubmitToCT, func(req []byte) (response []byte, err error) {
err = impl.SubmitToCT(req) err = impl.SubmitToCT(req)
return return
@ -593,11 +594,11 @@ func NewPublisherServer(rpc RPCServer, impl core.Publisher) (err error) {
// PublisherClient is a client to communicate with the Publisher Authority // PublisherClient is a client to communicate with the Publisher Authority
type PublisherClient struct { type PublisherClient struct {
rpc RPCClient rpc Client
} }
// NewPublisherClient constructs an RPC client // NewPublisherClient constructs an RPC client
func NewPublisherClient(client RPCClient) (pub PublisherClient, err error) { func NewPublisherClient(client Client) (pub PublisherClient, err error) {
pub = PublisherClient{rpc: client} pub = PublisherClient{rpc: client}
return return
} }
@ -612,7 +613,7 @@ func (pub PublisherClient) SubmitToCT(der []byte) (err error) {
// //
// CertificateAuthorityClient / Server // CertificateAuthorityClient / Server
// -> IssueCertificate // -> IssueCertificate
func NewCertificateAuthorityServer(rpc RPCServer, impl core.CertificateAuthority) (err error) { func NewCertificateAuthorityServer(rpc Server, impl core.CertificateAuthority) (err error) {
rpc.Handle(MethodIssueCertificate, func(req []byte) (response []byte, err error) { rpc.Handle(MethodIssueCertificate, func(req []byte) (response []byte, err error) {
var icReq issueCertificateRequest var icReq issueCertificateRequest
err = json.Unmarshal(req, &icReq) err = json.Unmarshal(req, &icReq)
@ -679,11 +680,11 @@ func NewCertificateAuthorityServer(rpc RPCServer, impl core.CertificateAuthority
// CertificateAuthorityClient is a client to communicate with the CA. // CertificateAuthorityClient is a client to communicate with the CA.
type CertificateAuthorityClient struct { type CertificateAuthorityClient struct {
rpc RPCClient rpc Client
} }
// NewCertificateAuthorityClient constructs an RPC client // NewCertificateAuthorityClient constructs an RPC client
func NewCertificateAuthorityClient(client RPCClient) (cac CertificateAuthorityClient, err error) { func NewCertificateAuthorityClient(client Client) (cac CertificateAuthorityClient, err error) {
cac = CertificateAuthorityClient{rpc: client} cac = CertificateAuthorityClient{rpc: client}
return return
} }
@ -745,7 +746,7 @@ func (cac CertificateAuthorityClient) GenerateOCSP(signRequest core.OCSPSigningR
} }
// NewStorageAuthorityServer constructs an RPC server // NewStorageAuthorityServer constructs an RPC server
func NewStorageAuthorityServer(rpc RPCServer, impl core.StorageAuthority) error { func NewStorageAuthorityServer(rpc Server, impl core.StorageAuthority) error {
rpc.Handle(MethodUpdateRegistration, func(req []byte) (response []byte, err error) { rpc.Handle(MethodUpdateRegistration, func(req []byte) (response []byte, err error) {
var reg core.Registration var reg core.Registration
if err = json.Unmarshal(req, &reg); err != nil { if err = json.Unmarshal(req, &reg); err != nil {
@ -1034,7 +1035,7 @@ func NewStorageAuthorityServer(rpc RPCServer, impl core.StorageAuthority) error
} }
sct, err := impl.GetSCTReceipt(gsctReq.Serial, gsctReq.LogID) sct, err := impl.GetSCTReceipt(gsctReq.Serial, gsctReq.LogID)
jsonResponse, err := json.Marshal(core.RPCSignedCertificateTimestamp(sct)) jsonResponse, err := json.Marshal(core.SignedCertificateTimestamp(sct))
if err != nil { if err != nil {
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
errorCondition(MethodGetSCTReceipt, err, req) errorCondition(MethodGetSCTReceipt, err, req)
@ -1045,7 +1046,7 @@ func NewStorageAuthorityServer(rpc RPCServer, impl core.StorageAuthority) error
}) })
rpc.Handle(MethodAddSCTReceipt, func(req []byte) (response []byte, err error) { rpc.Handle(MethodAddSCTReceipt, func(req []byte) (response []byte, err error) {
var sct core.RPCSignedCertificateTimestamp var sct core.SignedCertificateTimestamp
err = json.Unmarshal(req, &sct) err = json.Unmarshal(req, &sct)
if err != nil { if err != nil {
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
@ -1068,11 +1069,11 @@ func NewStorageAuthorityServer(rpc RPCServer, impl core.StorageAuthority) error
// StorageAuthorityClient is a client to communicate with the Storage Authority // StorageAuthorityClient is a client to communicate with the Storage Authority
type StorageAuthorityClient struct { type StorageAuthorityClient struct {
rpc RPCClient rpc Client
} }
// NewStorageAuthorityClient constructs an RPC client // NewStorageAuthorityClient constructs an RPC client
func NewStorageAuthorityClient(client RPCClient) (sac StorageAuthorityClient, err error) { func NewStorageAuthorityClient(client Client) (sac StorageAuthorityClient, err error) {
sac = StorageAuthorityClient{rpc: client} sac = StorageAuthorityClient{rpc: client}
return return
} }
@ -1124,10 +1125,10 @@ func (cac StorageAuthorityClient) GetAuthorization(id string) (authz core.Author
} }
// GetLatestValidAuthorization sends a request to get an Authorization by RegID, Identifier // GetLatestValidAuthorization sends a request to get an Authorization by RegID, Identifier
func (cac StorageAuthorityClient) GetLatestValidAuthorization(registrationId int64, identifier core.AcmeIdentifier) (authz core.Authorization, err error) { func (cac StorageAuthorityClient) GetLatestValidAuthorization(registrationID int64, identifier core.AcmeIdentifier) (authz core.Authorization, err error) {
var lvar latestValidAuthorizationRequest var lvar latestValidAuthorizationRequest
lvar.RegID = registrationId lvar.RegID = registrationID
lvar.Identifier = identifier lvar.Identifier = identifier
data, err := json.Marshal(lvar) data, err := json.Marshal(lvar)
@ -1331,6 +1332,8 @@ func (cac StorageAuthorityClient) CountCertificatesRange(start, end time.Time) (
return return
} }
// GetSCTReceipt retrieves an SCT according to the serial number of a certificate
// and the logID of the log to which it was submitted.
func (cac StorageAuthorityClient) GetSCTReceipt(serial string, logID string) (receipt core.SignedCertificateTimestamp, err error) { func (cac StorageAuthorityClient) GetSCTReceipt(serial string, logID string) (receipt core.SignedCertificateTimestamp, err error) {
var gsctReq struct { var gsctReq struct {
Serial string Serial string
@ -1353,6 +1356,7 @@ func (cac StorageAuthorityClient) GetSCTReceipt(serial string, logID string) (re
return return
} }
// AddSCTReceipt adds a new SCT to the database.
func (cac StorageAuthorityClient) AddSCTReceipt(sct core.SignedCertificateTimestamp) (err error) { func (cac StorageAuthorityClient) AddSCTReceipt(sct core.SignedCertificateTimestamp) (err error) {
data, err := json.Marshal(sct) data, err := json.Marshal(sct)
if err != nil { if err != nil {

View File

@ -11,6 +11,7 @@ import (
"net/url" "net/url"
"strings" "strings"
// Provide access to the MySQL driver
_ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/go-sql-driver/mysql" _ "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/go-sql-driver/mysql"
gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1" gorp "github.com/letsencrypt/boulder/Godeps/_workspace/src/gopkg.in/gorp.v1"
"github.com/letsencrypt/boulder/core" "github.com/letsencrypt/boulder/core"

View File

@ -212,16 +212,16 @@ func (ssa *SQLStorageAuthority) GetAuthorization(id string) (authz core.Authoriz
} }
// GetLatestValidAuthorization gets the valid authorization with biggest expire date for a given domain and registrationId // GetLatestValidAuthorization gets the valid authorization with biggest expire date for a given domain and registrationId
func (ssa *SQLStorageAuthority) GetLatestValidAuthorization(registrationId int64, identifier core.AcmeIdentifier) (authz core.Authorization, err error) { func (ssa *SQLStorageAuthority) GetLatestValidAuthorization(registrationID int64, identifier core.AcmeIdentifier) (authz core.Authorization, err error) {
ident, err := json.Marshal(identifier) ident, err := json.Marshal(identifier)
if err != nil { if err != nil {
return return
} }
var auth core.Authorization var auth core.Authorization
err = ssa.dbMap.SelectOne(&auth, "SELECT id FROM authz "+ err = ssa.dbMap.SelectOne(&auth, "SELECT id FROM authz "+
"WHERE identifier = :identifier AND registrationID = :registrationId AND status = 'valid' "+ "WHERE identifier = :identifier AND registrationID = :registrationID AND status = 'valid' "+
"ORDER BY expires DESC LIMIT 1", "ORDER BY expires DESC LIMIT 1",
map[string]interface{}{"identifier": string(ident), "registrationId": registrationId}) map[string]interface{}{"identifier": string(ident), "registrationID": registrationID})
if err != nil { if err != nil {
return return
} }
@ -229,15 +229,18 @@ func (ssa *SQLStorageAuthority) GetLatestValidAuthorization(registrationId int64
return ssa.GetAuthorization(auth.ID) return ssa.GetAuthorization(auth.ID)
} }
// TooManyCertificatesError indicates that the number of certificates returned by
// CountCertificates exceeded the hard-coded limit of 10,000 certificates.
type TooManyCertificatesError string type TooManyCertificatesError string
func (t TooManyCertificatesError) Error() string { func (t TooManyCertificatesError) Error() string {
return string(t) return string(t)
} }
// CountCertificates returns the number of certificates issued within a time // CountCertificatesByName returns the number of certificates issued within a time
// period containing DNSNames that are equal to, or subdomains of, the given // period containing DNSNames that are equal to, or subdomains of, the given
// domain name. // domain name.
//
// The highest count this function can return is 10,000. If there are more // The highest count this function can return is 10,000. If there are more
// certificates than that matching the provided domain name, it will return // certificates than that matching the provided domain name, it will return
// TooManyCertificatesError. // TooManyCertificatesError.

View File

@ -168,10 +168,10 @@ func TestAddAuthorization(t *testing.T) {
} }
func CreateDomainAuth(t *testing.T, domainName string, sa *SQLStorageAuthority) (authz core.Authorization) { func CreateDomainAuth(t *testing.T, domainName string, sa *SQLStorageAuthority) (authz core.Authorization) {
return CreateDomainAuthWithRegId(t, domainName, sa, 42) return CreateDomainAuthWithRegID(t, domainName, sa, 42)
} }
func CreateDomainAuthWithRegId(t *testing.T, domainName string, sa *SQLStorageAuthority, regID int64) (authz core.Authorization) { func CreateDomainAuthWithRegID(t *testing.T, domainName string, sa *SQLStorageAuthority, regID int64) (authz core.Authorization) {
// create pending auth // create pending auth
authz, err := sa.NewPendingAuthorization(core.Authorization{RegistrationID: regID, Challenges: []core.Challenge{core.Challenge{}}}) authz, err := sa.NewPendingAuthorization(core.Authorization{RegistrationID: regID, Challenges: []core.Challenge{core.Challenge{}}})
@ -212,7 +212,7 @@ func TestGetLatestValidAuthorizationBasic(t *testing.T) {
reg := satest.CreateWorkingRegistration(t, sa) reg := satest.CreateWorkingRegistration(t, sa)
// authorize "example.org" // authorize "example.org"
authz = CreateDomainAuthWithRegId(t, "example.org", sa, reg.ID) authz = CreateDomainAuthWithRegID(t, "example.org", sa, reg.ID)
// finalize auth // finalize auth
authz.Status = core.StatusValid authz.Status = core.StatusValid
@ -243,7 +243,7 @@ func TestGetLatestValidAuthorizationMultiple(t *testing.T) {
reg := satest.CreateWorkingRegistration(t, sa) reg := satest.CreateWorkingRegistration(t, sa)
// create invalid authz // create invalid authz
authz := CreateDomainAuthWithRegId(t, domain, sa, reg.ID) authz := CreateDomainAuthWithRegID(t, domain, sa, reg.ID)
exp := time.Now().AddDate(0, 0, 10) // expire in 10 day exp := time.Now().AddDate(0, 0, 10) // expire in 10 day
authz.Expires = &exp authz.Expires = &exp
authz.Status = core.StatusInvalid authz.Status = core.StatusInvalid
@ -255,7 +255,7 @@ func TestGetLatestValidAuthorizationMultiple(t *testing.T) {
test.AssertError(t, err, "Should not have found a valid auth for "+domain) test.AssertError(t, err, "Should not have found a valid auth for "+domain)
// create valid auth // create valid auth
authz = CreateDomainAuthWithRegId(t, domain, sa, reg.ID) authz = CreateDomainAuthWithRegID(t, domain, sa, reg.ID)
exp = time.Now().AddDate(0, 0, 1) // expire in 1 day exp = time.Now().AddDate(0, 0, 1) // expire in 1 day
authz.Expires = &exp authz.Expires = &exp
authz.Status = core.StatusValid authz.Status = core.StatusValid
@ -271,7 +271,7 @@ func TestGetLatestValidAuthorizationMultiple(t *testing.T) {
test.AssertEquals(t, authz.RegistrationID, reg.ID) test.AssertEquals(t, authz.RegistrationID, reg.ID)
// create a newer auth // create a newer auth
newAuthz := CreateDomainAuthWithRegId(t, domain, sa, reg.ID) newAuthz := CreateDomainAuthWithRegID(t, domain, sa, reg.ID)
exp = time.Now().AddDate(0, 0, 2) // expire in 2 day exp = time.Now().AddDate(0, 0, 2) // expire in 2 day
newAuthz.Expires = &exp newAuthz.Expires = &exp
newAuthz.Status = core.StatusValid newAuthz.Status = core.StatusValid

24
test.sh
View File

@ -63,13 +63,23 @@ function run() {
} }
function run_and_comment() { function run_and_comment() {
if [ "x${TRAVIS}" = "x" ] || [ "${TRAVIS_PULL_REQUEST}" == "false" ] || [ ! -f "${GITHUB_SECRET_FILE}" ] ; then echo "$@"
run "$@" result=$("$@" 2>&1)
echo ${result}
if [ "x${result}" == "x" ]; then
update_status --state success
echo "Success: $@"
else else
result=$(run "$@") FAILURE=1
local status=$? update_status --state failure
# Only send a comment if exit code > 0 echo "[!] FAILURE: $@"
if [ ${status} -ne 0 ] ; then fi
# If this is a travis PR run, post a comment
if [ "x${TRAVIS}" != "x" ] && [ "${TRAVIS_PULL_REQUEST}" != "false" ] && [ -f "${GITHUB_SECRET_FILE}" ] ; then
# If the output is non-empty, post a comment and mark this as a failure
if [ "x${result}" -ne "x" ] ; then
echo $'```\n'${result}$'\n```' | github-pr-status --authfile $GITHUB_SECRET_FILE \ echo $'```\n'${result}$'\n```' | github-pr-status --authfile $GITHUB_SECRET_FILE \
--owner "letsencrypt" --repo "boulder" \ --owner "letsencrypt" --repo "boulder" \
comment --pr "${TRAVIS_PULL_REQUEST}" -b - comment --pr "${TRAVIS_PULL_REQUEST}" -b -
@ -157,7 +167,7 @@ fi
# #
if [[ "$RUN" =~ "lint" ]] ; then if [[ "$RUN" =~ "lint" ]] ; then
start_context "test/golint" start_context "test/golint"
[ -x "$(which golint)" ] && run golint ./... run_and_comment golint -min_confidence=0.81 ./...
end_context #test/golint end_context #test/golint
fi fi

View File

@ -245,7 +245,7 @@ func TestSimpleHttpTLS(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPSPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPSPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
finChall, err := va.validateSimpleHTTP(ident, chall) finChall, err := va.validateSimpleHTTP(ident, chall)
@ -288,7 +288,7 @@ func TestSimpleHttp(t *testing.T) {
} }
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: badPort}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: badPort}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
invalidChall, err := va.validateSimpleHTTP(ident, chall) invalidChall, err := va.validateSimpleHTTP(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
@ -296,7 +296,7 @@ func TestSimpleHttp(t *testing.T) {
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem) test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, stats, clock.Default()) va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
finChall, err := va.validateSimpleHTTP(ident, chall) finChall, err := va.validateSimpleHTTP(ident, chall)
test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertEquals(t, finChall.Status, core.StatusValid)
@ -375,7 +375,7 @@ func TestSimpleHttpRedirectLookup(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
chall.Token = pathMoved chall.Token = pathMoved
@ -437,7 +437,7 @@ func TestSimpleHttpRedirectLoop(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
finChall, err := va.validateSimpleHTTP(ident, chall) finChall, err := va.validateSimpleHTTP(ident, chall)
@ -457,7 +457,7 @@ func TestDvsni(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
finChall, err := va.validateDvsni(ident, chall) finChall, err := va.validateDvsni(ident, chall)
@ -517,7 +517,7 @@ func TestDVSNIWithTLSError(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
invalidChall, err := va.validateDvsni(ident, chall) invalidChall, err := va.validateDvsni(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
@ -660,7 +660,7 @@ func TestHttp(t *testing.T) {
} }
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: badPort}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: badPort}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
invalidChall, err := va.validateHTTP01(ident, chall) invalidChall, err := va.validateHTTP01(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
@ -668,7 +668,7 @@ func TestHttp(t *testing.T) {
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem) test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, stats, clock.Default()) va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
t.Logf("Trying to validate: %+v\n", chall) t.Logf("Trying to validate: %+v\n", chall)
finChall, err := va.validateHTTP01(ident, chall) finChall, err := va.validateHTTP01(ident, chall)
@ -743,7 +743,7 @@ func TestHTTPRedirectLookup(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
setChallengeToken(&chall, pathMoved) setChallengeToken(&chall, pathMoved)
@ -801,7 +801,7 @@ func TestHTTPRedirectLoop(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
finChall, err := va.validateHTTP01(ident, chall) finChall, err := va.validateHTTP01(ident, chall)
@ -836,7 +836,7 @@ func TestTLSSNI(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
log.Clear() log.Clear()
finChall, err := va.validateTLSSNI01(ident, chall) finChall, err := va.validateTLSSNI01(ident, chall)
@ -903,7 +903,7 @@ func TestTLSError(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
invalidChall, err := va.validateTLSSNI01(ident, chall) invalidChall, err := va.validateTLSSNI01(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid) test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
@ -921,7 +921,7 @@ func TestValidateHTTP(t *testing.T) {
test.AssertNotError(t, err, "failed to get test server port") test.AssertNotError(t, err, "failed to get test server port")
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -986,7 +986,7 @@ func TestValidateTLSSNI01(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{TLSPort: port}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -1004,7 +1004,7 @@ func TestValidateTLSSNI01(t *testing.T) {
func TestValidateTLSSNINotSane(t *testing.T) { func TestValidateTLSSNINotSane(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) // no calls made va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) // no calls made
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -1026,7 +1026,7 @@ func TestValidateTLSSNINotSane(t *testing.T) {
func TestUpdateValidations(t *testing.T) { func TestUpdateValidations(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -1082,7 +1082,7 @@ func TestCAAChecking(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
va.IssuerDomain = "letsencrypt.org" va.IssuerDomain = "letsencrypt.org"
for _, caaTest := range tests { for _, caaTest := range tests {
present, valid, err := va.CheckCAARecords(core.AcmeIdentifier{Type: "dns", Value: caaTest.Domain}) present, valid, err := va.CheckCAARecords(core.AcmeIdentifier{Type: "dns", Value: caaTest.Domain})
@ -1115,7 +1115,7 @@ func TestCAAChecking(t *testing.T) {
func TestDNSValidationFailure(t *testing.T) { func TestDNSValidationFailure(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -1152,7 +1152,7 @@ func TestDNSValidationInvalid(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -1166,7 +1166,7 @@ func TestDNSValidationInvalid(t *testing.T) {
func TestDNSValidationNotSane(t *testing.T) { func TestDNSValidationNotSane(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -1197,7 +1197,7 @@ func TestDNSValidationNotSane(t *testing.T) {
func TestDNSValidationServFail(t *testing.T) { func TestDNSValidationServFail(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA
@ -1248,7 +1248,7 @@ func TestDNSValidationNoServer(t *testing.T) {
func TestDNSValidationLive(t *testing.T) { func TestDNSValidationLive(t *testing.T) {
stats, _ := statsd.NewNoopClient() stats, _ := statsd.NewNoopClient()
va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default()) va := NewValidationAuthorityImpl(&PortConfig{}, stats, clock.Default())
va.DNSResolver = &mocks.MockDNS{} va.DNSResolver = &mocks.DNSResolver{}
mockRA := &MockRegistrationAuthority{} mockRA := &MockRegistrationAuthority{}
va.RA = mockRA va.RA = mockRA

View File

@ -38,10 +38,14 @@ const (
IssuerPath = "/acme/issuer-cert" IssuerPath = "/acme/issuer-cert"
BuildIDPath = "/build" BuildIDPath = "/build"
// Not included in net/http // StatusRateLimited is not in net/http
StatusRateLimited = 429 StatusRateLimited = 429
) )
// WebFrontEndImpl provides all the logic for Boulder's web-facing interface,
// i.e., ACME. Its members configure the paths for various ACME functions,
// plus a few other data items used in ACME. Its methods are primarily handlers
// for HTTPS requests for the various ACME functions.
type WebFrontEndImpl struct { type WebFrontEndImpl struct {
RA core.RegistrationAuthority RA core.RegistrationAuthority
SA core.StorageGetter SA core.StorageGetter
@ -302,6 +306,8 @@ func addCacheHeader(w http.ResponseWriter, age float64) {
w.Header().Add("Cache-Control", fmt.Sprintf("public, max-age=%.f", age)) w.Header().Add("Cache-Control", fmt.Sprintf("public, max-age=%.f", age))
} }
// Directory is an HTTP request handler that simply provides the directory
// object stored in the WFE's DirectoryJSON member.
func (wfe *WebFrontEndImpl) Directory(response http.ResponseWriter, request *http.Request) { func (wfe *WebFrontEndImpl) Directory(response http.ResponseWriter, request *http.Request) {
response.Header().Set("Content-Type", "application/json") response.Header().Set("Content-Type", "application/json")
response.Write(wfe.DirectoryJSON) response.Write(wfe.DirectoryJSON)
@ -553,8 +559,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques
// Use an explicitly typed variable. Otherwise `go vet' incorrectly complains // Use an explicitly typed variable. Otherwise `go vet' incorrectly complains
// that reg.ID is a string being passed to %d. // that reg.ID is a string being passed to %d.
var id int64 = reg.ID regURL := fmt.Sprintf("%s%d", wfe.RegBase, reg.ID)
regURL := fmt.Sprintf("%s%d", wfe.RegBase, id)
responseBody, err := json.Marshal(reg) responseBody, err := json.Marshal(reg)
if err != nil { if err != nil {
logEvent.Error = err.Error() logEvent.Error = err.Error()
@ -833,6 +838,8 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
} }
} }
// Challenge handles POST requests to challenge URLs. Such requests are clients'
// responses to the server's challenges.
func (wfe *WebFrontEndImpl) Challenge( func (wfe *WebFrontEndImpl) Challenge(
response http.ResponseWriter, response http.ResponseWriter,
request *http.Request) { request *http.Request) {

View File

@ -213,7 +213,7 @@ func setupWFE(t *testing.T) WebFrontEndImpl {
wfe.log.SyslogWriter = mocks.NewSyslogWriter() wfe.log.SyslogWriter = mocks.NewSyslogWriter()
wfe.RA = &MockRegistrationAuthority{} wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
wfe.stats, _ = statsd.NewNoopClient() wfe.stats, _ = statsd.NewNoopClient()
wfe.SubscriberAgreementURL = agreementURL wfe.SubscriberAgreementURL = agreementURL
@ -533,7 +533,7 @@ func TestIssueCertificate(t *testing.T) {
wfe := setupWFE(t) wfe := setupWFE(t)
mux, err := wfe.Handler() mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers") test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mockLog := wfe.log.SyslogWriter.(*mocks.MockSyslogWriter) mockLog := wfe.log.SyslogWriter.(*mocks.SyslogWriter)
// The mock CA we use always returns the same test certificate, with a Not // The mock CA we use always returns the same test certificate, with a Not
// Before of 2015-09-22. Since we're currently using a real RA instead of a // Before of 2015-09-22. Since we're currently using a real RA instead of a
@ -548,10 +548,10 @@ func TestIssueCertificate(t *testing.T) {
// authorized, etc. // authorized, etc.
stats, _ := statsd.NewNoopClient(nil) stats, _ := statsd.NewNoopClient(nil)
ra := ra.NewRegistrationAuthorityImpl(fakeClock, wfe.log, stats, cmd.RateLimitConfig{}) ra := ra.NewRegistrationAuthorityImpl(fakeClock, wfe.log, stats, cmd.RateLimitConfig{})
ra.SA = &mocks.MockSA{} ra.SA = &mocks.StorageAuthority{}
ra.CA = &MockCA{} ra.CA = &MockCA{}
ra.PA = &MockPA{} ra.PA = &MockPA{}
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
wfe.RA = &ra wfe.RA = &ra
responseWriter := httptest.NewRecorder() responseWriter := httptest.NewRecorder()
@ -670,7 +670,7 @@ func TestChallenge(t *testing.T) {
wfe := setupWFE(t) wfe := setupWFE(t)
wfe.RA = &MockRegistrationAuthority{} wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
responseWriter := httptest.NewRecorder() responseWriter := httptest.NewRecorder()
var key jose.JsonWebKey var key jose.JsonWebKey
@ -706,7 +706,7 @@ func TestNewRegistration(t *testing.T) {
test.AssertNotError(t, err, "Problem setting up HTTP handlers") test.AssertNotError(t, err, "Problem setting up HTTP handlers")
wfe.RA = &MockRegistrationAuthority{} wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
wfe.stats, _ = statsd.NewNoopClient() wfe.stats, _ = statsd.NewNoopClient()
wfe.SubscriberAgreementURL = agreementURL wfe.SubscriberAgreementURL = agreementURL
@ -878,7 +878,7 @@ func makeRevokeRequestJSON() ([]byte, error) {
// registration when GetRegistrationByKey is called, and we want to get a // registration when GetRegistrationByKey is called, and we want to get a
// NoSuchRegistrationError for tests that pass regCheck = false to verifyPOST. // NoSuchRegistrationError for tests that pass regCheck = false to verifyPOST.
type mockSANoSuchRegistration struct { type mockSANoSuchRegistration struct {
mocks.MockSA mocks.StorageAuthority
} }
func (msa mockSANoSuchRegistration) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) { func (msa mockSANoSuchRegistration) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) {
@ -901,7 +901,7 @@ func TestRevokeCertificateCertKey(t *testing.T) {
test.AssertNotError(t, err, "Failed to make revokeRequestJSON") test.AssertNotError(t, err, "Failed to make revokeRequestJSON")
wfe := setupWFE(t) wfe := setupWFE(t)
wfe.SA = &mockSANoSuchRegistration{mocks.MockSA{}} wfe.SA = &mockSANoSuchRegistration{mocks.StorageAuthority{}}
responseWriter := httptest.NewRecorder() responseWriter := httptest.NewRecorder()
nonce, err := wfe.nonceService.Nonce() nonce, err := wfe.nonceService.Nonce()
@ -991,7 +991,7 @@ func TestRevokeCertificateAlreadyRevoked(t *testing.T) {
wfe := setupWFE(t) wfe := setupWFE(t)
wfe.RA = &MockRegistrationAuthority{} wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &mockSANoSuchRegistration{mocks.MockSA{}} wfe.SA = &mockSANoSuchRegistration{mocks.StorageAuthority{}}
wfe.stats, _ = statsd.NewNoopClient() wfe.stats, _ = statsd.NewNoopClient()
wfe.SubscriberAgreementURL = agreementURL wfe.SubscriberAgreementURL = agreementURL
responseWriter := httptest.NewRecorder() responseWriter := httptest.NewRecorder()
@ -1012,7 +1012,7 @@ func TestAuthorization(t *testing.T) {
test.AssertNotError(t, err, "Problem setting up HTTP handlers") test.AssertNotError(t, err, "Problem setting up HTTP handlers")
wfe.RA = &MockRegistrationAuthority{} wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
wfe.stats, _ = statsd.NewNoopClient() wfe.stats, _ = statsd.NewNoopClient()
responseWriter := httptest.NewRecorder() responseWriter := httptest.NewRecorder()
@ -1100,7 +1100,7 @@ func TestRegistration(t *testing.T) {
test.AssertNotError(t, err, "Problem setting up HTTP handlers") test.AssertNotError(t, err, "Problem setting up HTTP handlers")
wfe.RA = &MockRegistrationAuthority{} wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
wfe.stats, _ = statsd.NewNoopClient() wfe.stats, _ = statsd.NewNoopClient()
wfe.SubscriberAgreementURL = agreementURL wfe.SubscriberAgreementURL = agreementURL
responseWriter := httptest.NewRecorder() responseWriter := httptest.NewRecorder()
@ -1191,7 +1191,7 @@ func TestTermsRedirect(t *testing.T) {
wfe := setupWFE(t) wfe := setupWFE(t)
wfe.RA = &MockRegistrationAuthority{} wfe.RA = &MockRegistrationAuthority{}
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
wfe.stats, _ = statsd.NewNoopClient() wfe.stats, _ = statsd.NewNoopClient()
wfe.SubscriberAgreementURL = agreementURL wfe.SubscriberAgreementURL = agreementURL
@ -1227,14 +1227,14 @@ func TestGetCertificate(t *testing.T) {
wfe := setupWFE(t) wfe := setupWFE(t)
wfe.CertCacheDuration = time.Second * 10 wfe.CertCacheDuration = time.Second * 10
wfe.CertNoCacheExpirationWindow = time.Hour * 24 * 7 wfe.CertNoCacheExpirationWindow = time.Hour * 24 * 7
wfe.SA = &mocks.MockSA{} wfe.SA = &mocks.StorageAuthority{}
certPemBytes, _ := ioutil.ReadFile("test/178.crt") certPemBytes, _ := ioutil.ReadFile("test/178.crt")
certBlock, _ := pem.Decode(certPemBytes) certBlock, _ := pem.Decode(certPemBytes)
responseWriter := httptest.NewRecorder() responseWriter := httptest.NewRecorder()
mockLog := wfe.log.SyslogWriter.(*mocks.MockSyslogWriter) mockLog := wfe.log.SyslogWriter.(*mocks.SyslogWriter)
mockLog.Clear() mockLog.Clear()
// Valid serial, cached // Valid serial, cached
@ -1284,7 +1284,7 @@ func TestGetCertificate(t *testing.T) {
test.AssertEquals(t, responseWriter.Body.String(), `{"type":"urn:acme:error:malformed","detail":"Certificate not found"}`) test.AssertEquals(t, responseWriter.Body.String(), `{"type":"urn:acme:error:malformed","detail":"Certificate not found"}`)
} }
func assertCsrLogged(t *testing.T, mockLog *mocks.MockSyslogWriter) { func assertCsrLogged(t *testing.T, mockLog *mocks.SyslogWriter) {
matches := mockLog.GetAllMatching("^\\[AUDIT\\] Certificate request JSON=") matches := mockLog.GetAllMatching("^\\[AUDIT\\] Certificate request JSON=")
test.Assert(t, len(matches) == 1, test.Assert(t, len(matches) == 1,
fmt.Sprintf("Incorrect number of certificate request log entries: %d", fmt.Sprintf("Incorrect number of certificate request log entries: %d",
@ -1301,7 +1301,7 @@ func TestLogCsrPem(t *testing.T) {
err := json.Unmarshal([]byte(certificateRequestJSON), &certificateRequest) err := json.Unmarshal([]byte(certificateRequestJSON), &certificateRequest)
test.AssertNotError(t, err, "Unable to parse certificateRequest") test.AssertNotError(t, err, "Unable to parse certificateRequest")
mockSA := mocks.MockSA{} mockSA := mocks.StorageAuthority{}
reg, err := mockSA.GetRegistration(789) reg, err := mockSA.GetRegistration(789)
test.AssertNotError(t, err, "Unable to get registration") test.AssertNotError(t, err, "Unable to get registration")
@ -1310,7 +1310,7 @@ func TestLogCsrPem(t *testing.T) {
req.RemoteAddr = "12.34.98.76" req.RemoteAddr = "12.34.98.76"
req.Header.Set("X-Forwarded-For", "10.0.0.1,172.16.0.1") req.Header.Set("X-Forwarded-For", "10.0.0.1,172.16.0.1")
mockLog := wfe.log.SyslogWriter.(*mocks.MockSyslogWriter) mockLog := wfe.log.SyslogWriter.(*mocks.SyslogWriter)
mockLog.Clear() mockLog.Clear()
wfe.logCsr(req, certificateRequest, reg) wfe.logCsr(req, certificateRequest, reg)
@ -1334,7 +1334,7 @@ func TestLengthRequired(t *testing.T) {
} }
type mockSADifferentStoredKey struct { type mockSADifferentStoredKey struct {
mocks.MockSA mocks.StorageAuthority
} }
func (sa mockSADifferentStoredKey) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) { func (sa mockSADifferentStoredKey) GetRegistrationByKey(jwk jose.JsonWebKey) (core.Registration, error) {
@ -1349,7 +1349,7 @@ func (sa mockSADifferentStoredKey) GetRegistrationByKey(jwk jose.JsonWebKey) (co
func TestVerifyPOSTUsesStoredKey(t *testing.T) { func TestVerifyPOSTUsesStoredKey(t *testing.T) {
wfe := setupWFE(t) wfe := setupWFE(t)
wfe.SA = &mockSADifferentStoredKey{mocks.MockSA{}} wfe.SA = &mockSADifferentStoredKey{mocks.StorageAuthority{}}
// signRequest signs with test1Key, but our special mock returns a // signRequest signs with test1Key, but our special mock returns a
// registration with test2Key // registration with test2Key
_, _, _, err := wfe.verifyPOST(makePostRequest(signRequest(t, `{"resource":"foo"}`, &wfe.nonceService)), true, "foo") _, _, _, err := wfe.verifyPOST(makePostRequest(signRequest(t, `{"resource":"foo"}`, &wfe.nonceService)), true, "foo")