Record initial application CSR.

Fixes https://github.com/letsencrypt/boulder/issues/493.
Also, modify MockSyslogWriter so that it implements the SyslogWriter interface
(no pointer receivers).
This commit is contained in:
Jacob Hoffman-Andrews 2015-07-22 11:37:12 -07:00
parent ce4ca429a6
commit 6952aebeb3
4 changed files with 53 additions and 19 deletions

View File

@ -143,14 +143,10 @@ type AcmeIdentifier struct {
// CertificateRequest is just a CSR together with
// URIs pointing to authorizations that should collectively
// authorize the certificate being requsted.
//
// This type is never marshaled, since we only ever receive
// it from the client. So it carries some additional information
// that is useful internally. (We rely on Go's case-insensitive
// JSON unmarshal to properly unmarshal client requests.)
type CertificateRequest struct {
CSR *x509.CertificateRequest // The CSR
Authorizations []AcmeURL // Links to Authorization over the account key
Bytes []byte // The original bytes of the CSR, for logging.
}
type rawCertificateRequest struct {
@ -172,6 +168,7 @@ func (cr *CertificateRequest) UnmarshalJSON(data []byte) error {
cr.CSR = csr
cr.Authorizations = raw.Authorizations
cr.Bytes = raw.CSR
return nil
}

View File

@ -126,47 +126,47 @@ func (msw *MockSyslogWriter) Clear() {
}
// Close releases resources. No other methods may be called after this.
func (msw *MockSyslogWriter) Close() error {
func (msw MockSyslogWriter) Close() error {
msw.closeChan <- struct{}{}
return nil
}
// Alert logs at LOG_ALERT
func (msw *MockSyslogWriter) Alert(m string) error {
func (msw MockSyslogWriter) Alert(m string) error {
return msw.write(m, syslog.LOG_ALERT)
}
// Crit logs at LOG_CRIT
func (msw *MockSyslogWriter) Crit(m string) error {
func (msw MockSyslogWriter) Crit(m string) error {
return msw.write(m, syslog.LOG_CRIT)
}
// Debug logs at LOG_DEBUG
func (msw *MockSyslogWriter) Debug(m string) error {
func (msw MockSyslogWriter) Debug(m string) error {
return msw.write(m, syslog.LOG_DEBUG)
}
// Emerg logs at LOG_EMERG
func (msw *MockSyslogWriter) Emerg(m string) error {
func (msw MockSyslogWriter) Emerg(m string) error {
return msw.write(m, syslog.LOG_EMERG)
}
// Err logs at LOG_ERR
func (msw *MockSyslogWriter) Err(m string) error {
func (msw MockSyslogWriter) Err(m string) error {
return msw.write(m, syslog.LOG_ERR)
}
// Info logs at LOG_INFO
func (msw *MockSyslogWriter) Info(m string) error {
func (msw MockSyslogWriter) Info(m string) error {
return msw.write(m, syslog.LOG_INFO)
}
// Notice logs at LOG_NOTICE
func (msw *MockSyslogWriter) Notice(m string) error {
func (msw MockSyslogWriter) Notice(m string) error {
return msw.write(m, syslog.LOG_NOTICE)
}
// Warning logs at LOG_WARNING
func (msw *MockSyslogWriter) Warning(m string) error {
func (msw MockSyslogWriter) Warning(m string) error {
return msw.write(m, syslog.LOG_WARNING)
}

View File

@ -9,6 +9,7 @@ import (
"bytes"
"crypto/x509"
"database/sql"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@ -624,6 +625,11 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
}
}
func (wfe *WebFrontEndImpl) logCsr(cr core.CertificateRequest) {
wfe.log.Audit(fmt.Sprintf("Certificate request CSR=%s",
base64.StdEncoding.EncodeToString(cr.Bytes)))
}
// NewCertificate is used by clients to request the issuance of a cert for an
// authorized identifier.
func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request *http.Request) {
@ -659,6 +665,7 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
wfe.sendError(response, "Error unmarshaling certificate request", err, http.StatusBadRequest)
return
}
wfe.logCsr(init)
logEvent.Extra["Authorizations"] = init.Authorizations
logEvent.Extra["CSRDNSNames"] = init.CSR.DNSNames
logEvent.Extra["CSREmailAddresses"] = init.CSR.EmailAddresses

View File

@ -14,6 +14,7 @@ import (
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io"
"io/ioutil"
"log/syslog"
@ -128,8 +129,6 @@ wk6Oiadty3eQqSBJv0HnpmiEdQVffIK5Pg4M8Dd+aOBnEkbopAJOuA==
"5dd9c885526136d810fc7640f5ba56281e2b75fa3ff7c91a7d23bab7fd4"
)
var log = mocks.UseMockLog()
type MockSA struct {
// empty
}
@ -332,6 +331,7 @@ func setupWFE(t *testing.T) WebFrontEndImpl {
wfe.NewCert = wfe.BaseURL + NewCertPath
wfe.CertBase = wfe.BaseURL + CertPath
wfe.SubscriberAgreementURL = agreementURL
wfe.log.SyslogWriter = mocks.NewSyslogWriter()
return wfe
}
@ -496,6 +496,7 @@ func TestIssueCertificate(t *testing.T) {
wfe := setupWFE(t)
mux, err := wfe.Handler()
test.AssertNotError(t, err, "Problem setting up HTTP handlers")
mockLog := wfe.log.SyslogWriter.(*mocks.MockSyslogWriter)
// TODO: Use a mock RA so we can test various conditions of authorized, not authorized, etc.
ra := ra.NewRegistrationAuthorityImpl()
@ -572,6 +573,7 @@ func TestIssueCertificate(t *testing.T) {
"{\"type\":\"urn:acme:error:unauthorized\",\"detail\":\"Error creating new cert :: Invalid signature on CSR\"}")
// Valid, signed JWS body, payload has a CSR with no DNS names
mockLog.Clear()
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter, &http.Request{
Method: "POST",
@ -583,12 +585,14 @@ func TestIssueCertificate(t *testing.T) {
test.AssertEquals(t,
responseWriter.Body.String(),
"{\"type\":\"urn:acme:error:unauthorized\",\"detail\":\"Error creating new cert :: Key not authorized for name Oh hi\"}")
assertCsrLogged(t, mockLog)
// Valid, signed JWS body, payload has a valid CSR but no authorizations:
// {
// "csr": "MIIBK...",
// "authorizations: []
// }
mockLog.Clear()
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter, &http.Request{
Method: "POST",
@ -600,8 +604,9 @@ func TestIssueCertificate(t *testing.T) {
test.AssertEquals(t,
responseWriter.Body.String(),
"{\"type\":\"urn:acme:error:unauthorized\",\"detail\":\"Error creating new cert :: Key not authorized for name meep.com\"}")
assertCsrLogged(t, mockLog)
log.Clear()
mockLog.Clear()
responseWriter.Body.Reset()
wfe.NewCertificate(responseWriter, &http.Request{
Method: "POST",
@ -610,6 +615,7 @@ func TestIssueCertificate(t *testing.T) {
"authorizations": ["valid"]
}`, &wfe.nonceService)),
})
assertCsrLogged(t, mockLog)
randomCertDer, _ := hex.DecodeString(GoodTestCert)
test.AssertEquals(t,
responseWriter.Body.String(),
@ -623,7 +629,7 @@ func TestIssueCertificate(t *testing.T) {
test.AssertEquals(
t, responseWriter.Header().Get("Content-Type"),
"application/pkix-cert")
reqlogs := log.GetAllMatching(`Certificate request - successful`)
reqlogs := mockLog.GetAllMatching(`Certificate request - successful`)
test.AssertEquals(t, len(reqlogs), 1)
test.AssertEquals(t, reqlogs[0].Priority, syslog.LOG_NOTICE)
test.AssertContains(t, reqlogs[0].Message, `[AUDIT] `)
@ -1206,5 +1212,29 @@ func TestGetCertificate(t *testing.T) {
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"}`)
}
func assertCsrLogged(t *testing.T, mockLog *mocks.MockSyslogWriter) {
matches := mockLog.GetAllMatching("^\\[AUDIT\\] Certificate request CSR=")
test.Assert(t, len(matches) == 1,
fmt.Sprintf("Incorrect number of certificate request log entries: %d",
len(matches)))
test.AssertEquals(t, matches[0].Priority, syslog.LOG_NOTICE)
}
func TestLogCsrPem(t *testing.T) {
const certificateRequestJson = `{
"csr": "MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAycX3ca-fViOuRWF38mssORISFxbJvspDfhPGRBZDxJ63NIqQzupB-6dp48xkcX7Z_KDaRJStcpJT2S0u33moNT4FHLklQBETLhExDk66cmlz6Xibp3LGZAwhWuec7wJoEwIgY8oq4rxihIyGq7HVIJoq9DqZGrUgfZMDeEJqbphukQOaXGEop7mD-eeu8-z5EVkB1LiJ6Yej6R8MAhVPHzG5fyOu6YVo6vY6QgwjRLfZHNj5XthxgPIEETZlUbiSoI6J19GYHvLURBTy5Ys54lYAPIGfNwcIBAH4gtH9FrYcDY68R22rp4iuxdvkf03ZWiT0F2W1y7_C9B2jayTzvQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAHd6Do9DIZ2hvdt1GwBXYjsqprZidT_DYOMfYcK17KlvdkFT58XrBH88ulLZ72NXEpiFMeTyzfs3XEyGq_Bbe7TBGVYZabUEh-LOskYwhgcOuThVN7tHnH5rhN-gb7cEdysjTb1QL-vOUwYgV75CB6PE5JVYK-cQsMIVvo0Kz4TpNgjJnWzbcH7h0mtvub-fCv92vBPjvYq8gUDLNrok6rbg05tdOJkXsF2G_W-Q6sf2Fvx0bK5JeH4an7P7cXF9VG9nd4sRt5zd-L3IcyvHVKxNhIJXZVH0AOqh_1YrKI9R0QKQiZCEy0xN1okPlcaIVaFhb7IKAHPxTI3r5f72LXY"
}`
wfe := setupWFE(t)
var certificateRequest core.CertificateRequest
err := json.Unmarshal([]byte(certificateRequestJson), &certificateRequest)
test.AssertNotError(t, err, "Unable to parse certificateRequest")
wfe.logCsr(certificateRequest)
mockLog := wfe.log.SyslogWriter.(*mocks.MockSyslogWriter)
matches := mockLog.GetAllMatching("Certificate request")
test.Assert(t, len(matches) == 1,
"Incorrect number of certificate request log entries")
test.AssertEquals(t, matches[0].Priority, syslog.LOG_NOTICE)
test.AssertEquals(t, matches[0].Message, `[AUDIT] Certificate request CSR=MIICWTCCAUECAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAycX3ca+fViOuRWF38mssORISFxbJvspDfhPGRBZDxJ63NIqQzupB+6dp48xkcX7Z/KDaRJStcpJT2S0u33moNT4FHLklQBETLhExDk66cmlz6Xibp3LGZAwhWuec7wJoEwIgY8oq4rxihIyGq7HVIJoq9DqZGrUgfZMDeEJqbphukQOaXGEop7mD+eeu8+z5EVkB1LiJ6Yej6R8MAhVPHzG5fyOu6YVo6vY6QgwjRLfZHNj5XthxgPIEETZlUbiSoI6J19GYHvLURBTy5Ys54lYAPIGfNwcIBAH4gtH9FrYcDY68R22rp4iuxdvkf03ZWiT0F2W1y7/C9B2jayTzvQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAHd6Do9DIZ2hvdt1GwBXYjsqprZidT/DYOMfYcK17KlvdkFT58XrBH88ulLZ72NXEpiFMeTyzfs3XEyGq/Bbe7TBGVYZabUEh+LOskYwhgcOuThVN7tHnH5rhN+gb7cEdysjTb1QL+vOUwYgV75CB6PE5JVYK+cQsMIVvo0Kz4TpNgjJnWzbcH7h0mtvub+fCv92vBPjvYq8gUDLNrok6rbg05tdOJkXsF2G/W+Q6sf2Fvx0bK5JeH4an7P7cXF9VG9nd4sRt5zd+L3IcyvHVKxNhIJXZVH0AOqh/1YrKI9R0QKQiZCEy0xN1okPlcaIVaFhb7IKAHPxTI3r5f72LXY=`)
}