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:
parent
ce4ca429a6
commit
6952aebeb3
|
@ -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
|
||||
}
|
||||
|
||||
|
|
18
mocks/log.go
18
mocks/log.go
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=`)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue