Merge branch 'master' into ocsp-unflake-integration

Conflicts:
	test/amqp-integration-test.py
This commit is contained in:
Jacob Hoffman-Andrews 2015-10-22 14:30:37 -07:00
commit 305d7fad22
14 changed files with 594 additions and 359 deletions

View File

@ -17,8 +17,10 @@ import (
"io/ioutil"
"math/big"
"strings"
"sync"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
@ -48,6 +50,15 @@ var badSignatureAlgorithms = map[x509.SignatureAlgorithm]bool{
x509.ECDSAWithSHA1: true,
}
// Metrics for CA statistics
const (
// Increments when CA observes an HSM fault
metricHSMFaultObserved = "CA.OCSP.HSMFault.Observed"
// Increments when CA rejects a request due to an HSM fault
metricHSMFaultRejected = "CA.OCSP.HSMFault.Rejected"
)
// CertificateAuthorityImpl represents a CA that signs certificates, CRLs, and
// OCSP responses.
type CertificateAuthorityImpl struct {
@ -59,10 +70,15 @@ type CertificateAuthorityImpl struct {
Publisher core.Publisher
Clk clock.Clock // TODO(jmhodges): should be private, like log
log *blog.AuditLogger
stats statsd.Statter
Prefix int // Prepended to the serial number
ValidityPeriod time.Duration
NotAfter time.Time
MaxNames int
hsmFaultLock sync.Mutex
hsmFaultLastObserved time.Time
hsmFaultTimeout time.Duration
}
// NewCertificateAuthorityImpl creates a CA that talks to a remote CFSSL
@ -71,7 +87,7 @@ type CertificateAuthorityImpl struct {
// using CFSSL's authenticated signature scheme. A CA created in this way
// issues for a single profile on the remote signer, which is indicated
// by name in this constructor.
func NewCertificateAuthorityImpl(config cmd.CAConfig, clk clock.Clock, issuerCert string) (*CertificateAuthorityImpl, error) {
func NewCertificateAuthorityImpl(config cmd.CAConfig, clk clock.Clock, stats statsd.Statter, issuerCert string) (*CertificateAuthorityImpl, error) {
var ca *CertificateAuthorityImpl
var err error
logger := blog.GetAuditLogger()
@ -125,13 +141,15 @@ func NewCertificateAuthorityImpl(config cmd.CAConfig, clk clock.Clock, issuerCer
}
ca = &CertificateAuthorityImpl{
Signer: signer,
OCSPSigner: ocspSigner,
profile: config.Profile,
Prefix: config.SerialPrefix,
Clk: clk,
log: logger,
NotAfter: issuer.NotAfter,
Signer: signer,
OCSPSigner: ocspSigner,
profile: config.Profile,
Prefix: config.SerialPrefix,
Clk: clk,
log: logger,
stats: stats,
NotAfter: issuer.NotAfter,
hsmFaultTimeout: config.HSMFaultTimeout.Duration,
}
if config.Expiry == "" {
@ -172,8 +190,48 @@ func loadKey(keyConfig cmd.KeyConfig) (priv crypto.Signer, err error) {
return
}
// checkHSMFault checks whether there has been an HSM fault observed within the
// timeout window. CA methods that use the HSM should call this method right
// away, to minimize the performance impact of HSM outages.
func (ca *CertificateAuthorityImpl) checkHSMFault() error {
ca.hsmFaultLock.Lock()
defer ca.hsmFaultLock.Unlock()
// If no timeout is set, never gate on a fault
if ca.hsmFaultTimeout == 0 {
return nil
}
now := ca.Clk.Now()
timeout := ca.hsmFaultLastObserved.Add(ca.hsmFaultTimeout)
if now.Before(timeout) {
err := core.ServiceUnavailableError("HSM is unavailable")
ca.log.WarningErr(err)
ca.stats.Inc(metricHSMFaultRejected, 1, 1.0)
return err
}
return nil
}
// noteHSMFault updates the CA's state with regard to HSM faults. CA methods
// that use an HSM should pass errors that might be HSM errors to this method.
func (ca *CertificateAuthorityImpl) noteHSMFault(err error) {
ca.hsmFaultLock.Lock()
defer ca.hsmFaultLock.Unlock()
if err != nil {
ca.stats.Inc(metricHSMFaultObserved, 1, 1.0)
ca.hsmFaultLastObserved = ca.Clk.Now()
}
return
}
// GenerateOCSP produces a new OCSP response and returns it
func (ca *CertificateAuthorityImpl) GenerateOCSP(xferObj core.OCSPSigningRequest) ([]byte, error) {
if err := ca.checkHSMFault(); err != nil {
return nil, err
}
cert, err := x509.ParseCertificate(xferObj.CertDER)
if err != nil {
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
@ -189,6 +247,7 @@ func (ca *CertificateAuthorityImpl) GenerateOCSP(xferObj core.OCSPSigningRequest
}
ocspResponse, err := ca.OCSPSigner.Sign(signRequest)
ca.noteHSMFault(err)
return ocspResponse, err
}
@ -204,6 +263,11 @@ func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string, reasonCode
func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest, regID int64) (core.Certificate, error) {
emptyCert := core.Certificate{}
var err error
if err := ca.checkHSMFault(); err != nil {
return emptyCert, err
}
key, ok := csr.PublicKey.(crypto.PublicKey)
if !ok {
err = core.MalformedRequestError("Invalid public key in CSR.")
@ -309,6 +373,7 @@ func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest
}
certPEM, err := ca.Signer.Sign(req)
ca.noteHSMFault(err)
if err != nil {
err = core.InternalServerError(err.Error())
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3

View File

@ -112,6 +112,7 @@ type testCtx struct {
reg core.Registration
pa core.PolicyAuthority
fc clock.FakeClock
stats *mocks.Statter
cleanUp func()
}
@ -150,9 +151,10 @@ func setup(t *testing.T) *testCtx {
Key: cmd.KeyConfig{
File: caKeyFile,
},
Expiry: "8760h",
LifespanOCSP: "45m",
MaxNames: 2,
Expiry: "8760h",
LifespanOCSP: "45m",
MaxNames: 2,
HSMFaultTimeout: cmd.ConfigDuration{Duration: 60 * time.Second},
CFSSL: cfsslConfig.Config{
Signing: &cfsslConfig.Signing{
Profiles: map[string]*cfsslConfig.SigningProfile{
@ -188,7 +190,10 @@ func setup(t *testing.T) *testCtx {
},
},
}
return &testCtx{ssa, caConfig, reg, pa, fc, cleanUp}
stats := mocks.NewStatter()
return &testCtx{ssa, caConfig, reg, pa, fc, &stats, cleanUp}
}
func TestFailNoSerial(t *testing.T) {
@ -196,14 +201,14 @@ func TestFailNoSerial(t *testing.T) {
defer ctx.cleanUp()
ctx.caConfig.SerialPrefix = 0
_, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
_, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
test.AssertError(t, err, "CA should have failed with no SerialPrefix")
}
func TestIssueCertificate(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
@ -280,7 +285,7 @@ func TestIssueCertificate(t *testing.T) {
func TestRejectNoName(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
@ -297,7 +302,7 @@ func TestRejectNoName(t *testing.T) {
func TestRejectTooManyNames(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
@ -314,7 +319,7 @@ func TestRejectTooManyNames(t *testing.T) {
func TestDeduplication(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
@ -338,7 +343,7 @@ func TestDeduplication(t *testing.T) {
func TestRejectValidityTooLong(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
test.AssertNotError(t, err, "Failed to create CA")
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
@ -356,7 +361,7 @@ func TestRejectValidityTooLong(t *testing.T) {
func TestShortKey(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -372,7 +377,7 @@ func TestShortKey(t *testing.T) {
func TestRejectBadAlgorithm(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -389,7 +394,7 @@ func TestCapitalizedLetters(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ctx.caConfig.MaxNames = 3
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, caCertFile)
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
ca.SA = ctx.sa
@ -405,3 +410,70 @@ func TestCapitalizedLetters(t *testing.T) {
expected := []string{"capitalizedletters.com", "evenmorecaps.com", "morecaps.com"}
test.AssertDeepEquals(t, expected, parsedCert.DNSNames)
}
func TestHSMFaultTimeout(t *testing.T) {
ctx := setup(t)
defer ctx.cleanUp()
ca, err := NewCertificateAuthorityImpl(ctx.caConfig, ctx.fc, ctx.stats, caCertFile)
ca.Publisher = &mocks.Publisher{}
ca.PA = ctx.pa
ca.SA = ctx.sa
// Issue a certificate so that we can use it later
csr, _ := x509.ParseCertificateRequest(CNandSANCSR)
cert, err := ca.IssueCertificate(*csr, ctx.reg.ID)
ocspRequest := core.OCSPSigningRequest{
CertDER: cert.DER,
Status: "good",
}
// Swap in a bad signer
goodSigner := ca.Signer
badHSMErrorMessage := "This is really serious. You should wait"
badSigner := mocks.BadHSMSigner(badHSMErrorMessage)
badOCSPSigner := mocks.BadHSMOCSPSigner(badHSMErrorMessage)
// Cause the CA to enter the HSM fault condition
ca.Signer = badSigner
_, err = ca.IssueCertificate(*csr, ctx.reg.ID)
test.AssertError(t, err, "CA failed to return HSM error")
test.AssertEquals(t, err.Error(), badHSMErrorMessage)
// Check that the CA rejects the next call as the HSM being down
_, err = ca.IssueCertificate(*csr, ctx.reg.ID)
test.AssertError(t, err, "CA failed to persist HSM fault")
test.AssertEquals(t, err.Error(), "HSM is unavailable")
_, err = ca.GenerateOCSP(ocspRequest)
test.AssertError(t, err, "CA failed to persist HSM fault")
test.AssertEquals(t, err.Error(), "HSM is unavailable")
// Swap in a good signer and move the clock forward to clear the fault
ca.Signer = goodSigner
ctx.fc.Add(ca.hsmFaultTimeout)
ctx.fc.Add(10 * time.Second)
// Check that the CA has recovered
_, err = ca.IssueCertificate(*csr, ctx.reg.ID)
test.AssertNotError(t, err, "CA failed to recover from HSM fault")
_, err = ca.GenerateOCSP(ocspRequest)
// Check that GenerateOCSP can also trigger an HSM failure, in the same way
ca.OCSPSigner = badOCSPSigner
_, err = ca.GenerateOCSP(ocspRequest)
test.AssertError(t, err, "CA failed to return HSM error")
test.AssertEquals(t, err.Error(), badHSMErrorMessage)
_, err = ca.IssueCertificate(*csr, ctx.reg.ID)
test.AssertError(t, err, "CA failed to persist HSM fault")
test.AssertEquals(t, err.Error(), "HSM is unavailable")
_, err = ca.GenerateOCSP(ocspRequest)
test.AssertError(t, err, "CA failed to persist HSM fault")
test.AssertEquals(t, err.Error(), "HSM is unavailable")
// Verify that the appropriate stats got recorded for all this
test.AssertEquals(t, ctx.stats.Counters[metricHSMFaultObserved], int64(2))
test.AssertEquals(t, ctx.stats.Counters[metricHSMFaultRejected], int64(4))
}

View File

@ -39,7 +39,7 @@ func main() {
pa, err := policy.NewPolicyAuthorityImpl(paDbMap, c.PA.EnforcePolicyWhitelist)
cmd.FailOnError(err, "Couldn't create PA")
cai, err := ca.NewCertificateAuthorityImpl(c.CA, clock.Default(), c.Common.IssuerCert)
cai, err := ca.NewCertificateAuthorityImpl(c.CA, clock.Default(), stats, c.Common.IssuerCert)
cmd.FailOnError(err, "Failed to create CA impl")
cai.PA = pa

View File

@ -240,6 +240,8 @@ type CAConfig struct {
MaxConcurrentRPCServerRequests int64
HSMFaultTimeout ConfigDuration
// DebugAddr is the address to run the /debug handlers on.
DebugAddr string
}

View File

@ -93,6 +93,10 @@ type RateLimitedError string
// limit
type TooManyRPCRequestsError string
// ServiceUnavailableError indicates that a component is not available to
// satisfy a request
type ServiceUnavailableError string
func (e InternalServerError) Error() string { return string(e) }
func (e NotSupportedError) Error() string { return string(e) }
func (e MalformedRequestError) Error() string { return string(e) }
@ -105,6 +109,7 @@ func (e CertificateIssuanceError) Error() string { return string(e) }
func (e NoSuchRegistrationError) Error() string { return string(e) }
func (e RateLimitedError) Error() string { return string(e) }
func (e TooManyRPCRequestsError) Error() string { return string(e) }
func (e ServiceUnavailableError) Error() string { return string(e) }
// Base64 functions

View File

@ -6,6 +6,7 @@
package mocks
import (
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
@ -14,6 +15,11 @@ import (
"strings"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/info"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns"
@ -370,3 +376,61 @@ type Publisher struct {
func (*Publisher) SubmitToCT([]byte) error {
return nil
}
// BadHSMSigner represents a CFSSL signer that always returns a PKCS#11 error.
type BadHSMSigner string
// Info is a mock
func (bhs BadHSMSigner) Info(info.Req) (*info.Resp, error) {
return nil, nil
}
// Policy is a mock
func (bhs BadHSMSigner) Policy() *config.Signing {
return nil
}
// SetPolicy is a mock
func (bhs BadHSMSigner) SetPolicy(*config.Signing) {
return
}
// SigAlgo is a mock
func (bhs BadHSMSigner) SigAlgo() x509.SignatureAlgorithm {
return x509.UnknownSignatureAlgorithm
}
// Sign always returns a PKCS#11 error, in the format used by
// github.com/miekg/pkcs11
func (bhs BadHSMSigner) Sign(req signer.SignRequest) (cert []byte, err error) {
return nil, fmt.Errorf(string(bhs))
}
// BadHSMOCSPSigner represents a CFSSL OCSP signer that always returns a
// PKCS#11 error
type BadHSMOCSPSigner string
// Sign always returns a PKCS#11 error, in the format used by
// github.com/miekg/pkcs11
func (bhos BadHSMOCSPSigner) Sign(ocsp.SignRequest) ([]byte, error) {
return nil, fmt.Errorf(string(bhos))
}
// Statter is a stat counter that is a no-op except for locally handling Inc
// calls (which are most of what we use).
type Statter struct {
statsd.NoopClient
Counters map[string]int64
}
// Inc increments the indicated metric by the indicated value, in the Counters
// map maintained by the statter
func (s *Statter) Inc(metric string, value int64, rate float32) error {
s.Counters[metric] += value
return nil
}
// NewStatter returns an empty statter with all counters zero
func NewStatter() Statter {
return Statter{statsd.NoopClient{}, map[string]int64{}}
}

View File

@ -325,9 +325,7 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
// * IsCA is false
// * ExtKeyUsage only contains ExtKeyUsageServerAuth & ExtKeyUsageClientAuth
// * Subject only contains CommonName & Names
func (ra *RegistrationAuthorityImpl) MatchesCSR(
cert core.Certificate,
csr *x509.CertificateRequest) (err error) {
func (ra *RegistrationAuthorityImpl) MatchesCSR(cert core.Certificate, csr *x509.CertificateRequest) (err error) {
parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER))
if err != nil {
return
@ -345,7 +343,8 @@ func (ra *RegistrationAuthorityImpl) MatchesCSR(
err = core.InternalServerError("Generated certificate public key doesn't match CSR public key")
return
}
if len(csr.Subject.CommonName) > 0 && parsedCertificate.Subject.CommonName != csr.Subject.CommonName {
if len(csr.Subject.CommonName) > 0 &&
parsedCertificate.Subject.CommonName != strings.ToLower(csr.Subject.CommonName) {
err = core.InternalServerError("Generated certificate CommonName doesn't match CSR CommonName")
return
}

View File

@ -606,6 +606,8 @@ func TestNewCertificate(t *testing.T) {
authzFinalWWW, _ = sa.NewPendingAuthorization(authzFinalWWW)
sa.FinalizeAuthorization(authzFinalWWW)
// Check that we don't fail on case mismatches
ExampleCSR.Subject.CommonName = "www.NOT-example.com"
certRequest := core.CertificateRequest{
CSR: ExampleCSR,
}

View File

@ -235,6 +235,8 @@ func wrapError(err error) (rpcError rpcError) {
rpcError.Type = "TooManyRPCRequestsError"
case core.RateLimitedError:
rpcError.Type = "RateLimitedError"
case core.ServiceUnavailableError:
rpcError.Type = "ServiceUnavailableError"
}
}
return
@ -266,6 +268,8 @@ func unwrapError(rpcError rpcError) (err error) {
err = core.TooManyRPCRequestsError(rpcError.Value)
case "RateLimitedError":
err = core.RateLimitedError(rpcError.Value)
case "ServiceUnavailableError":
err = core.ServiceUnavailableError(rpcError.Value)
default:
err = errors.New(rpcError.Value)
}

View File

@ -171,7 +171,7 @@ def run_node_test():
# Issue the certificate and transform it from DER-encoded to PEM-encoded.
if subprocess.Popen('''
node test.js --email foo@letsencrypt.org --agree true \
--domains www.%s.com --new-reg http://localhost:4000/acme/new-reg \
--domains www.%s-TEST.com --new-reg http://localhost:4000/acme/new-reg \
--certKey %s --cert %s && \
openssl x509 -in %s -out %s -inform der -outform pem
''' % (domain, key_file, cert_file, cert_file, cert_file_pem),

View File

@ -111,7 +111,8 @@
}
}
},
"maxConcurrentRPCServerRequests": 16
"maxConcurrentRPCServerRequests": 16,
"hsmFaultTimeout": "300s"
},
"pa": {

85
wfe/context.go Normal file
View File

@ -0,0 +1,85 @@
package wfe
import (
"fmt"
"net/http"
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
)
type requestEvent struct {
ID string `json:",omitempty"`
RealIP string `json:",omitempty"`
ClientAddr string `json:",omitempty"`
Endpoint string `json:",omitempty"`
Method string `json:",omitempty"`
RequestTime time.Time `json:",omitempty"`
ResponseTime time.Time `json:",omitempty"`
Errors []string
Requester int64 `json:",omitempty"`
Contacts []*core.AcmeURL `json:",omitempty"`
Extra map[string]interface{} `json:",omitempty"`
}
func (e *requestEvent) AddError(msg string, args ...interface{}) {
e.Errors = append(e.Errors, fmt.Sprintf(msg, args...))
}
type wfeHandlerFunc func(*requestEvent, http.ResponseWriter, *http.Request)
func (f wfeHandlerFunc) ServeHTTP(e *requestEvent, w http.ResponseWriter, r *http.Request) {
f(e, w, r)
}
type wfeHandler interface {
ServeHTTP(e *requestEvent, w http.ResponseWriter, r *http.Request)
}
type topHandler struct {
wfe wfeHandler
log *blog.AuditLogger
clk clock.Clock
}
func (th *topHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logEvent := &requestEvent{
ID: core.NewToken(),
RealIP: r.Header.Get("X-Real-IP"),
ClientAddr: getClientAddr(r),
Method: r.Method,
RequestTime: time.Now(),
Extra: make(map[string]interface{}, 0),
}
if r.URL != nil {
logEvent.Endpoint = r.URL.String()
}
defer th.logEvent(logEvent)
th.wfe.ServeHTTP(logEvent, w, r)
}
func (th *topHandler) logEvent(logEvent *requestEvent) {
logEvent.ResponseTime = th.clk.Now()
var msg string
if len(logEvent.Errors) != 0 {
msg = "Terminated request"
} else {
msg = "Successful request"
}
th.log.InfoObject(msg, logEvent)
}
// Comma-separated list of HTTP clients involved in making this
// request, starting with the original requestor and ending with the
// remote end of our TCP connection (which is typically our own
// proxy).
func getClientAddr(r *http.Request) string {
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
return xff + "," + r.RemoteAddr
}
return r.RemoteAddr
}

File diff suppressed because it is too large Load Diff

View File

@ -271,7 +271,7 @@ func TestHandleFunc(t *testing.T) {
mux = http.NewServeMux()
rw = httptest.NewRecorder()
stubCalled = false
wfe.HandleFunc(mux, "/test", func(http.ResponseWriter, *http.Request) {
wfe.HandleFunc(mux, "/test", func(*requestEvent, http.ResponseWriter, *http.Request) {
stubCalled = true
}, allowed...)
req.URL = mustParseURL("/test")
@ -463,7 +463,7 @@ func TestIndexPOST(t *testing.T) {
wfe, _ := setupWFE(t)
responseWriter := httptest.NewRecorder()
url, _ := url.Parse("/")
wfe.Index(responseWriter, &http.Request{
wfe.Index(newRequestEvent(), responseWriter, &http.Request{
Method: "POST",
URL: url,
})
@ -474,7 +474,7 @@ func TestPOST404(t *testing.T) {
wfe, _ := setupWFE(t)
responseWriter := httptest.NewRecorder()
url, _ := url.Parse("/foobar")
wfe.Index(responseWriter, &http.Request{
wfe.Index(newRequestEvent(), responseWriter, &http.Request{
Method: "POST",
URL: url,
})
@ -488,7 +488,7 @@ func TestIndex(t *testing.T) {
responseWriter := httptest.NewRecorder()
url, _ := url.Parse("/")
wfe.Index(responseWriter, &http.Request{
wfe.Index(newRequestEvent(), responseWriter, &http.Request{
Method: "GET",
URL: url,
})
@ -501,7 +501,7 @@ func TestIndex(t *testing.T) {
responseWriter.Body.Reset()
responseWriter.Header().Del("Cache-Control")
url, _ = url.Parse("/foo")
wfe.Index(responseWriter, &http.Request{
wfe.Index(newRequestEvent(), responseWriter, &http.Request{
URL: url,
})
//test.AssertEquals(t, responseWriter.Code, http.StatusNotFound)
@ -564,7 +564,7 @@ func TestIssueCertificate(t *testing.T) {
// POST, but no body.
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter, &http.Request{
wfe.NewCertificate(newRequestEvent(), responseWriter, &http.Request{
Method: "POST",
Header: map[string][]string{
"Content-Length": []string{"0"},
@ -576,14 +576,14 @@ func TestIssueCertificate(t *testing.T) {
// POST, but body that isn't valid JWS
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter, makePostRequest("hi"))
wfe.NewCertificate(newRequestEvent(), responseWriter, makePostRequest("hi"))
test.AssertEquals(t,
responseWriter.Body.String(),
`{"type":"urn:acme:error:malformed","detail":"Unable to read/verify body :: Parse error reading JWS"}`)
// POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON.
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
wfe.NewCertificate(newRequestEvent(), responseWriter,
makePostRequest(signRequest(t, "foo", &wfe.nonceService)))
test.AssertEquals(t,
responseWriter.Body.String(),
@ -591,7 +591,7 @@ func TestIssueCertificate(t *testing.T) {
// Valid, signed JWS body, payload is '{}'
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
wfe.NewCertificate(newRequestEvent(), responseWriter,
makePostRequest(
signRequest(t, "{}", &wfe.nonceService)))
test.AssertEquals(t,
@ -600,7 +600,7 @@ func TestIssueCertificate(t *testing.T) {
// Valid, signed JWS body, payload is '{"resource":"new-cert"}'
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
wfe.NewCertificate(newRequestEvent(), responseWriter,
makePostRequest(signRequest(t, `{"resource":"new-cert"}`, &wfe.nonceService)))
test.AssertEquals(t,
responseWriter.Body.String(),
@ -611,7 +611,8 @@ func TestIssueCertificate(t *testing.T) {
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=foo.com | \
// sed 's/foo.com/fob.com/' | b64url
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
wfe.NewCertificate(newRequestEvent(),
responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIICVzCCAT8CAQAwEjEQMA4GA1UEAwwHZm9iLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKzHhqcMSTVjBu61vufGVmIYM4mMbWXgndHOUWnIqSKcNtFtPQ465tcZRT5ITIZWXGjsmgDrj31qvG3t5qLwyaF5hsTvFHK72nLMAQhdgM6481Qe9yaoaulWpkGr_9LVz4jQ9pGAaLVamXGpSxV-ipTOo79Sev4aZE8ksD9atEfWtcOD9w8_zj74vpWjTAHN49Q88chlChVqakn0zSfHPfS-jF8g0UTddBuF0Ti3sZChjxzbo6LwZ4182xX7XPnOLav3AGj0Su7j5XMl3OpenOrlWulWJeZIHq5itGW321j306XiGdbrdWH4K7JygICFds6oolwQRGBY6yinAtCgkTcCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBxPiHOtKuBxtvecMNtLkTSuTyEkusQGnjoFDaKe5oqwGYQgy0YBii2-BbaPmqS4ZaDc-vDz_RLeKH5ZiH-NliYR1V_CRtpFLQi18g_2pLQnZLVO3ENs-SM37nU_nBGn9O93t2bkssoM3fZmtgp3R2W7I_wvx7Z8oWKa4boTeBAg_q9Gmi6QskZBddK7A4S_vOR0frU6QSPK_ksPhvovp9fwb6CVKrlJWf556UwRPWgbkW39hvTxK2KHhrUEg3oawNkWde2jZtnZ9e-9zpw8-_5O0X7-YN0ucbFTfQybce_ReuLlGepiHT5bvVavBZoIvqw1XOgSMvGgZFU8tAWMBlj"
@ -624,7 +625,7 @@ func TestIssueCertificate(t *testing.T) {
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=meep.com | b64url
mockLog.Clear()
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter,
wfe.NewCertificate(newRequestEvent(), responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIICWDCCAUACAQAwEzERMA8GA1UEAwwIbWVlcC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaqzue57mgXEoGTZZoVkkCZraebWgXI8irX2BgQB1A3iZa9onxGPMcWQMxhSuUisbEJi4UkMcVST12HX01rUwhj41UuBxJvI1w4wvdstssTAaa9c9tsQ5-UED2bFRL1MsyBdbmCF_-pu3i-ZIYqWgiKbjVBe3nlAVbo77zizwp3Y4Tp1_TBOwTAuFkHePmkNT63uPm9My_hNzsSm1o-Q519Cf7ry-JQmOVgz_jIgFVGFYJ17EV3KUIpUuDShuyCFATBQspgJSN2DoXRUlQjXXkNTj23OxxdT_cVLcLJjytyG6e5izME2R2aCkDBWIc1a4_sRJ0R396auPXG6KhJ7o_AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEALu046p76aKgvoAEHFINkMTgKokPXf9mZ4IZx_BKz-qs1MPMxVtPIrQDVweBH6tYT7Hfj2naLry6SpZ3vUNP_FYeTFWgW1V03LiqacX-QQgbEYtn99Dt3ScGyzb7EH833ztb3vDJ_-ha_CJplIrg-kHBBrlLFWXhh-I9K1qLRTNpbhZ18ooFde4Sbhkw9o9fKivGhx9aYr7ZbjRsNtKit_DsG1nwEXz53TMJ2vB9IQY29coJv_n5NFLkvBfzbG5faRNiFcimPYBO2jFdaA2mWzfxltLtwMF_dBwzTXDpMo3TVT9zEdV8YpsWqr63igqGDZVpKenlkqvRTeGJVayVuMA"
@ -637,7 +638,7 @@ func TestIssueCertificate(t *testing.T) {
mockLog.Clear()
responseWriter.Body.Reset()
// openssl req -outform der -new -nodes -key wfe/test/178.key -subj /CN=not-an-example.com | b64url
wfe.NewCertificate(responseWriter,
wfe.NewCertificate(newRequestEvent(), responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIICYjCCAUoCAQAwHTEbMBkGA1UEAwwSbm90LWFuLWV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmqs7nue5oFxKBk2WaFZJAma2nm1oFyPIq19gYEAdQN4mWvaJ8RjzHFkDMYUrlIrGxCYuFJDHFUk9dh19Na1MIY-NVLgcSbyNcOML3bLbLEwGmvXPbbEOflBA9mxUS9TLMgXW5ghf_qbt4vmSGKloIim41QXt55QFW6O-84s8Kd2OE6df0wTsEwLhZB3j5pDU-t7j5vTMv4Tc7EptaPkOdfQn-68viUJjlYM_4yIBVRhWCdexFdylCKVLg0obsghQEwULKYCUjdg6F0VJUI115DU49tzscXU_3FS3CyY8rchunuYszBNkdmgpAwViHNWuP7ESdEd_emrj1xuioSe6PwIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAE_T1nWU38XVYL28hNVSXU0rW5IBUKtbvr0qAkD4kda4HmQRTYkt-LNSuvxoZCC9lxijjgtJi-OJe_DCTdZZpYzewlVvcKToWSYHYQ6Wm1-fxxD_XzphvZOujpmBySchdiz7QSVWJmVZu34XD5RJbIcrmj_cjRt42J1hiTFjNMzQu9U6_HwIMmliDL-soFY2RTvvZf-dAFvOUQ-Wbxt97eM1PbbmxJNWRhbAmgEpe9PWDPTpqV5AK56VAa991cQ1P8ZVmPss5hvwGWhOtpnpTZVHN3toGNYFKqxWPboirqushQlfKiFqT9rpRgM3-mFjOHidGqsKEkTdmfSVlVEk3oo="
@ -675,7 +676,7 @@ func TestGetChallenge(t *testing.T) {
req, err := http.NewRequest(method, challengeURL, nil)
test.AssertNotError(t, err, "Could not make NewRequest")
wfe.Challenge(resp, req)
wfe.Challenge(newRequestEvent(), resp, req)
test.AssertEquals(t,
resp.Code,
http.StatusAccepted)
@ -714,7 +715,7 @@ func TestChallenge(t *testing.T) {
test.AssertNotError(t, err, "Could not unmarshal testing key")
challengeURL := "/acme/challenge/valid/23"
wfe.Challenge(responseWriter,
wfe.Challenge(newRequestEvent(), responseWriter,
makePostRequestWithPath(challengeURL,
signRequest(t, `{"resource":"challenge"}`, &wfe.nonceService)))
@ -732,7 +733,7 @@ func TestChallenge(t *testing.T) {
// Expired challenges should be inaccessible
challengeURL = "/acme/challenge/expired/23"
responseWriter = httptest.NewRecorder()
wfe.Challenge(responseWriter,
wfe.Challenge(newRequestEvent(), responseWriter,
makePostRequestWithPath(challengeURL,
signRequest(t, `{"resource":"challenge"}`, &wfe.nonceService)))
test.AssertEquals(t, responseWriter.Code, http.StatusNotFound)
@ -839,7 +840,7 @@ func TestNewRegistration(t *testing.T) {
nonce, err = wfe.nonceService.Nonce()
test.AssertNotError(t, err, "Unable to create nonce")
result, err = signer.Sign([]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"`+agreementURL+`"}`), nonce)
wfe.NewRegistration(responseWriter,
wfe.NewRegistration(newRequestEvent(), responseWriter,
makePostRequest(result.FullSerialize()))
var reg core.Registration
@ -875,7 +876,7 @@ func TestNewRegistration(t *testing.T) {
test.AssertNotError(t, err, "Unable to create nonce")
result, err = signer.Sign([]byte(`{"resource":"new-reg","contact":["tel:123456789"],"agreement":"`+agreementURL+`"}`), nonce)
wfe.NewRegistration(responseWriter,
wfe.NewRegistration(newRequestEvent(), responseWriter,
makePostRequest(result.FullSerialize()))
test.AssertEquals(t,
responseWriter.Body.String(),
@ -943,7 +944,7 @@ func TestRevokeCertificateCertKey(t *testing.T) {
nonce, err := wfe.nonceService.Nonce()
test.AssertNotError(t, err, "Unable to create nonce")
result, _ := signer.Sign(revokeRequestJSON, nonce)
wfe.RevokeCertificate(responseWriter,
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
makePostRequest(result.FullSerialize()))
test.AssertEquals(t, responseWriter.Code, 200)
test.AssertEquals(t, responseWriter.Body.String(), "")
@ -967,7 +968,7 @@ func TestRevokeCertificateAccountKey(t *testing.T) {
nonce, err := wfe.nonceService.Nonce()
test.AssertNotError(t, err, "Unable to create nonce")
result, _ := accountKeySigner.Sign(revokeRequestJSON, nonce)
wfe.RevokeCertificate(responseWriter,
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
makePostRequest(result.FullSerialize()))
test.AssertEquals(t, responseWriter.Code, 200)
test.AssertEquals(t, responseWriter.Body.String(), "")
@ -991,7 +992,7 @@ func TestRevokeCertificateWrongKey(t *testing.T) {
test.AssertNotError(t, err, "Unable to create revoke request")
result, _ := accountKeySigner2.Sign(revokeRequestJSON, nonce)
wfe.RevokeCertificate(responseWriter,
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
makePostRequest(result.FullSerialize()))
test.AssertEquals(t, responseWriter.Code, 403)
test.AssertEquals(t, responseWriter.Body.String(),
@ -1033,7 +1034,7 @@ func TestRevokeCertificateAlreadyRevoked(t *testing.T) {
nonce, err := wfe.nonceService.Nonce()
test.AssertNotError(t, err, "Unable to create nonce")
result, _ := signer.Sign(revokeRequestJSON, nonce)
wfe.RevokeCertificate(responseWriter,
wfe.RevokeCertificate(newRequestEvent(), responseWriter,
makePostRequest(result.FullSerialize()))
test.AssertEquals(t, responseWriter.Code, 409)
test.AssertEquals(t, responseWriter.Body.String(),
@ -1056,7 +1057,7 @@ func TestAuthorization(t *testing.T) {
// POST, but no body.
responseWriter.Body.Reset()
wfe.NewAuthorization(responseWriter, &http.Request{
wfe.NewAuthorization(newRequestEvent(), responseWriter, &http.Request{
Method: "POST",
Header: map[string][]string{
"Content-Length": []string{"0"},
@ -1066,12 +1067,12 @@ func TestAuthorization(t *testing.T) {
// POST, but body that isn't valid JWS
responseWriter.Body.Reset()
wfe.NewAuthorization(responseWriter, makePostRequest("hi"))
wfe.NewAuthorization(newRequestEvent(), responseWriter, makePostRequest("hi"))
test.AssertEquals(t, responseWriter.Body.String(), `{"type":"urn:acme:error:malformed","detail":"Unable to read/verify body :: Parse error reading JWS"}`)
// POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON.
responseWriter.Body.Reset()
wfe.NewAuthorization(responseWriter,
wfe.NewAuthorization(newRequestEvent(), responseWriter,
makePostRequest(signRequest(t, "foo", &wfe.nonceService)))
test.AssertEquals(t,
responseWriter.Body.String(),
@ -1080,7 +1081,7 @@ func TestAuthorization(t *testing.T) {
// Same signed body, but payload modified by one byte, breaking signature.
// should fail JWS verification.
responseWriter.Body.Reset()
wfe.NewAuthorization(responseWriter, makePostRequest(`
wfe.NewAuthorization(newRequestEvent(), responseWriter, makePostRequest(`
{
"header": {
"alg": "RS256",
@ -1099,7 +1100,7 @@ func TestAuthorization(t *testing.T) {
`{"type":"urn:acme:error:malformed","detail":"Unable to read/verify body :: JWS verification error"}`)
responseWriter.Body.Reset()
wfe.NewAuthorization(responseWriter,
wfe.NewAuthorization(newRequestEvent(), responseWriter,
makePostRequest(signRequest(t, `{"resource":"new-authz","identifier":{"type":"dns","value":"test.com"}}`, &wfe.nonceService)))
test.AssertEquals(
@ -1118,7 +1119,7 @@ func TestAuthorization(t *testing.T) {
// Expired authorizations should be inaccessible
authzURL := "/acme/authz/expired"
responseWriter = httptest.NewRecorder()
wfe.Authorization(responseWriter, &http.Request{
wfe.Authorization(newRequestEvent(), responseWriter, &http.Request{
Method: "GET",
URL: mustParseURL(authzURL),
})
@ -1164,7 +1165,7 @@ func TestRegistration(t *testing.T) {
responseWriter.Body.Reset()
// Test POST invalid JSON
wfe.Registration(responseWriter, makePostRequestWithPath("/2", "invalid"))
wfe.Registration(newRequestEvent(), responseWriter, makePostRequestWithPath("/2", "invalid"))
test.AssertEquals(t,
responseWriter.Body.String(),
`{"type":"urn:acme:error:malformed","detail":"Unable to read/verify body :: Parse error reading JWS"}`)
@ -1182,7 +1183,7 @@ func TestRegistration(t *testing.T) {
test.AssertNotError(t, err, "Unable to create nonce")
result, err := signer.Sign([]byte(`{"resource":"reg","agreement":"`+agreementURL+`"}`), nonce)
test.AssertNotError(t, err, "Unable to sign")
wfe.Registration(responseWriter,
wfe.Registration(newRequestEvent(), responseWriter,
makePostRequestWithPath("/2", result.FullSerialize()))
test.AssertEquals(t,
responseWriter.Body.String(),
@ -1202,7 +1203,7 @@ func TestRegistration(t *testing.T) {
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"https://letsencrypt.org/im-bad"}`), nonce)
// Test POST valid JSON with registration up in the mock
wfe.Registration(responseWriter,
wfe.Registration(newRequestEvent(), responseWriter,
makePostRequestWithPath("/1", result.FullSerialize()))
test.AssertEquals(t,
responseWriter.Body.String(),
@ -1214,7 +1215,7 @@ func TestRegistration(t *testing.T) {
test.AssertNotError(t, err, "Unable to create nonce")
result, err = signer.Sign([]byte(`{"resource":"reg","agreement":"`+agreementURL+`"}`), nonce)
test.AssertNotError(t, err, "Couldn't sign")
wfe.Registration(responseWriter,
wfe.Registration(newRequestEvent(), responseWriter,
makePostRequestWithPath("/1", result.FullSerialize()))
test.AssertNotContains(t, responseWriter.Body.String(), "urn:acme:error")
links := responseWriter.Header()["Link"]
@ -1229,7 +1230,7 @@ func TestTermsRedirect(t *testing.T) {
responseWriter := httptest.NewRecorder()
path, _ := url.Parse("/terms")
wfe.Terms(responseWriter, &http.Request{
wfe.Terms(newRequestEvent(), responseWriter, &http.Request{
Method: "GET",
URL: path,
})
@ -1246,7 +1247,7 @@ func TestIssuer(t *testing.T) {
responseWriter := httptest.NewRecorder()
wfe.Issuer(responseWriter, &http.Request{
wfe.Issuer(newRequestEvent(), responseWriter, &http.Request{
Method: "GET",
})
test.AssertEquals(t, responseWriter.Code, http.StatusOK)
@ -1256,6 +1257,9 @@ func TestIssuer(t *testing.T) {
func TestGetCertificate(t *testing.T) {
wfe, _ := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
wfe.CertCacheDuration = time.Second * 10
wfe.CertNoCacheExpirationWindow = time.Hour * 24 * 7
@ -1270,12 +1274,13 @@ func TestGetCertificate(t *testing.T) {
// Valid serial, cached
req, _ := http.NewRequest("GET", "/acme/cert/0000000000000000000000000000000000b2", nil)
req.RemoteAddr = "192.168.0.1"
wfe.Certificate(responseWriter, req)
mux.ServeHTTP(responseWriter, req)
test.AssertEquals(t, responseWriter.Code, 200)
test.AssertEquals(t, responseWriter.Header().Get("Cache-Control"), "public, max-age=10")
test.AssertEquals(t, responseWriter.Header().Get("Content-Type"), "application/pkix-cert")
test.Assert(t, bytes.Compare(responseWriter.Body.Bytes(), certBlock.Bytes) == 0, "Certificates don't match")
t.Logf("UGH %#v", mockLog.GetAll()[0])
reqlogs := mockLog.GetAllMatching(`Successful request`)
test.AssertEquals(t, len(reqlogs), 1)
test.AssertEquals(t, reqlogs[0].Priority, syslog.LOG_INFO)
@ -1287,7 +1292,7 @@ func TestGetCertificate(t *testing.T) {
req, _ = http.NewRequest("GET", "/acme/cert/0000000000000000000000000000000000ff", nil)
req.RemoteAddr = "192.168.0.1"
req.Header.Set("X-Forwarded-For", "192.168.99.99")
wfe.Certificate(responseWriter, req)
mux.ServeHTTP(responseWriter, req)
test.AssertEquals(t, responseWriter.Code, 404)
test.AssertEquals(t, responseWriter.Header().Get("Cache-Control"), "public, max-age=0, no-cache")
test.AssertEquals(t, responseWriter.Body.String(), `{"type":"urn:acme:error:malformed","detail":"Certificate not found"}`)
@ -1300,7 +1305,7 @@ func TestGetCertificate(t *testing.T) {
// Invalid serial, no cache
responseWriter = httptest.NewRecorder()
req, _ = http.NewRequest("GET", "/acme/cert/nothex", nil)
wfe.Certificate(responseWriter, req)
mux.ServeHTTP(responseWriter, req)
test.AssertEquals(t, responseWriter.Code, 404)
test.AssertEquals(t, responseWriter.Header().Get("Cache-Control"), "public, max-age=0, no-cache")
test.AssertEquals(t, responseWriter.Body.String(), `{"type":"urn:acme:error:malformed","detail":"Certificate not found"}`)
@ -1308,7 +1313,7 @@ func TestGetCertificate(t *testing.T) {
// Invalid serial, no cache
responseWriter = httptest.NewRecorder()
req, _ = http.NewRequest("GET", "/acme/cert/00000000000000", nil)
wfe.Certificate(responseWriter, req)
mux.ServeHTTP(responseWriter, req)
test.AssertEquals(t, responseWriter.Code, 404)
test.AssertEquals(t, responseWriter.Header().Get("Cache-Control"), "public, max-age=0, no-cache")
test.AssertEquals(t, responseWriter.Body.String(), `{"type":"urn:acme:error:malformed","detail":"Certificate not found"}`)
@ -1350,7 +1355,7 @@ func TestLogCsrPem(t *testing.T) {
func TestLengthRequired(t *testing.T) {
wfe, _ := setupWFE(t)
_, _, _, err := wfe.verifyPOST(&http.Request{
_, _, _, err := wfe.verifyPOST(newRequestEvent(), &http.Request{
Method: "POST",
URL: mustParseURL("/"),
}, false, "resource")
@ -1378,7 +1383,7 @@ func TestVerifyPOSTUsesStoredKey(t *testing.T) {
wfe.SA = &mockSADifferentStoredKey{mocks.NewStorageAuthority(fc)}
// signRequest signs with test1Key, but our special mock returns a
// registration with test2Key
_, _, _, err := wfe.verifyPOST(makePostRequest(signRequest(t, `{"resource":"foo"}`, &wfe.nonceService)), true, "foo")
_, _, _, err := wfe.verifyPOST(newRequestEvent(), makePostRequest(signRequest(t, `{"resource":"foo"}`, &wfe.nonceService)), true, "foo")
test.AssertError(t, err, "No error returned when provided key differed from stored key.")
}
@ -1389,7 +1394,7 @@ func TestBadKeyCSR(t *testing.T) {
// CSR with a bad (512 bit RSA) key.
// openssl req -outform der -new -newkey rsa:512 -nodes -keyout foo.com.key
// -subj /CN=foo.com | base64 -w0 | sed -e 's,+,-,g' -e 's,/,_,g'
wfe.NewCertificate(responseWriter,
wfe.NewCertificate(newRequestEvent(), responseWriter,
makePostRequest(signRequest(t, `{
"resource":"new-cert",
"csr": "MIHLMHcCAQAwEjEQMA4GA1UEAwwHZm9vLmNvbTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDCZftp4x4owgjBnwOKfzihIPedT-BUmV2fuQPMqaUlc8yJUp13vcO5uxUlaBm8leM7Dj_sgTDP_JgykorlYo73AgMBAAGgADANBgkqhkiG9w0BAQsFAANBAEaQ2QBhweK-kp1ejQCedUhMit_wG-uTBtKnc3M82f6_fztLkhg1vWQ782nmhbEI5orXp6QtNHgJYnBpqA9Ut00"
@ -1422,3 +1427,7 @@ func TestStatusCodeFromError(t *testing.T) {
}
}
}
func newRequestEvent() *requestEvent {
return &requestEvent{Extra: make(map[string]interface{})}
}