Merge remote-tracking branch 'upstream/master' into errors
This commit is contained in:
commit
b094c81371
18
Dockerfile
18
Dockerfile
|
|
@ -1,19 +1,29 @@
|
|||
FROM golang:1.4.2
|
||||
|
||||
MAINTAINER J.C. Jones "jjones@letsencrypt.org"
|
||||
MAINTAINER William Budington "bill@eff.org"
|
||||
|
||||
# Install dependencies packages
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
libltdl-dev \
|
||||
rsyslog && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* \
|
||||
/tmp/* \
|
||||
/var/tmp/*
|
||||
|
||||
# Boulder exposes its web application at port TCP 4000
|
||||
EXPOSE 4000
|
||||
|
||||
# Assume the configuration is in /etc/boulder
|
||||
ENV BOULDER_CONFIG /go/src/github.com/letsencrypt/boulder/test/example-config.json
|
||||
ENV BOULDER_CONFIG /go/src/github.com/letsencrypt/boulder/test/boulder-config.json
|
||||
|
||||
# Copy in the Boulder sources
|
||||
RUN mkdir -p /go/src/github.com/letsencrypt/boulder
|
||||
COPY . /go/src/github.com/letsencrypt/boulder
|
||||
|
||||
# Build Boulder
|
||||
RUN go install \
|
||||
RUN go install -tags pkcs11 \
|
||||
github.com/letsencrypt/boulder/cmd/activity-monitor \
|
||||
github.com/letsencrypt/boulder/cmd/boulder \
|
||||
github.com/letsencrypt/boulder/cmd/boulder-ca \
|
||||
|
|
@ -22,4 +32,4 @@ RUN go install \
|
|||
github.com/letsencrypt/boulder/cmd/boulder-va \
|
||||
github.com/letsencrypt/boulder/cmd/boulder-wfe
|
||||
|
||||
CMD ["/go/bin/boulder"]
|
||||
CMD ["bash", "-c", "rsyslogd && /go/bin/boulder"]
|
||||
|
|
|
|||
|
|
@ -227,13 +227,13 @@ func (ca *CertificateAuthorityImpl) GenerateOCSP(xferObj core.OCSPSigningRequest
|
|||
|
||||
// RevokeCertificate revokes the trust of the Cert referred to by the provided Serial.
|
||||
func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string, reasonCode int) (err error) {
|
||||
certDER, err := ca.SA.GetCertificate(serial)
|
||||
coreCert, err := ca.SA.GetCertificate(serial)
|
||||
if err != nil {
|
||||
// AUDIT[ Revocation Requests ] 4e85d791-09c0-4ab3-a837-d3d67e945134
|
||||
ca.log.AuditErr(err)
|
||||
return err
|
||||
}
|
||||
cert, err := x509.ParseCertificate(certDER)
|
||||
cert, err := x509.ParseCertificate(coreCert.DER)
|
||||
if err != nil {
|
||||
// AUDIT[ Revocation Requests ] 4e85d791-09c0-4ab3-a837-d3d67e945134
|
||||
ca.log.AuditErr(err)
|
||||
|
|
|
|||
|
|
@ -405,14 +405,14 @@ func TestIssueCertificate(t *testing.T) {
|
|||
csr, _ := x509.ParseCertificateRequest(csrDER)
|
||||
|
||||
// Sign CSR
|
||||
certObj, err := ca.IssueCertificate(*csr, 1, FarFuture)
|
||||
issuedCert, err := ca.IssueCertificate(*csr, 1, FarFuture)
|
||||
test.AssertNotError(t, err, "Failed to sign certificate")
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Verify cert contents
|
||||
cert, err := x509.ParseCertificate(certObj.DER)
|
||||
cert, err := x509.ParseCertificate(issuedCert.DER)
|
||||
test.AssertNotError(t, err, "Certificate failed to parse")
|
||||
|
||||
test.AssertEquals(t, cert.Subject.CommonName, "not-example.com")
|
||||
|
|
@ -446,10 +446,10 @@ func TestIssueCertificate(t *testing.T) {
|
|||
|
||||
// Verify that the cert got stored in the DB
|
||||
serialString := core.SerialToString(cert.SerialNumber)
|
||||
certBytes, err := storageAuthority.GetCertificate(serialString)
|
||||
storedCert, err := storageAuthority.GetCertificate(serialString)
|
||||
test.AssertNotError(t, err,
|
||||
fmt.Sprintf("Certificate %s not found in database", serialString))
|
||||
test.Assert(t, bytes.Equal(certBytes, certObj.DER), "Retrieved cert not equal to issued cert.")
|
||||
test.Assert(t, bytes.Equal(issuedCert.DER, storedCert.DER), "Retrieved cert not equal to issued cert.")
|
||||
|
||||
certStatus, err := storageAuthority.GetCertificateStatus(serialString)
|
||||
test.AssertNotError(t, err,
|
||||
|
|
|
|||
|
|
@ -96,8 +96,8 @@ type StorageGetter interface {
|
|||
GetRegistration(int64) (Registration, error)
|
||||
GetRegistrationByKey(jose.JsonWebKey) (Registration, error)
|
||||
GetAuthorization(string) (Authorization, error)
|
||||
GetCertificate(string) ([]byte, error)
|
||||
GetCertificateByShortSerial(string) ([]byte, error)
|
||||
GetCertificate(string) (Certificate, error)
|
||||
GetCertificateByShortSerial(string) (Certificate, error)
|
||||
GetCertificateStatus(string) (CertificateStatus, error)
|
||||
AlreadyDeniedCSR([]string) (bool, error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -390,11 +390,11 @@ type Certificate struct {
|
|||
// * "revoked" - revoked
|
||||
Status AcmeStatus `db:"status"`
|
||||
|
||||
Serial string `db:"serial"`
|
||||
Digest string `db:"digest"`
|
||||
DER []byte `db:"der"`
|
||||
Issued time.Time `db:"issued"`
|
||||
Expires time.Time `db:"expires"`
|
||||
Serial string `db:"serial"`
|
||||
Digest string `db:"digest"`
|
||||
DER JsonBuffer `db:"der"`
|
||||
Issued time.Time `db:"issued"`
|
||||
Expires time.Time `db:"expires"`
|
||||
}
|
||||
|
||||
// Certificate.MatchesCSR tests the contents of a generated certificate to
|
||||
|
|
|
|||
|
|
@ -42,6 +42,12 @@ var BuildTime string
|
|||
|
||||
// Errors
|
||||
|
||||
// InternalServerError indicates that something has gone wrong unrelated to the
|
||||
// user's input, and will be considered by the Load Balancer as an indication
|
||||
// that this Boulder instance may be malfunctioning. Minimally, returning this
|
||||
// will cause an error page to be generated at the CDN/LB for the client.
|
||||
// Consequently, you should only use this error when Boulder's internal
|
||||
// constraints have been violated.
|
||||
type InternalServerError string
|
||||
type NotSupportedError string
|
||||
type MalformedRequestError string
|
||||
|
|
|
|||
|
|
@ -61,17 +61,32 @@ func validateEmail(address string) (err error) {
|
|||
domain := strings.ToLower(splitEmail[len(splitEmail)-1])
|
||||
var mx []*net.MX
|
||||
mx, err = net.LookupMX(domain)
|
||||
if err != nil {
|
||||
err = core.InternalServerError(err.Error())
|
||||
return
|
||||
}
|
||||
if len(mx) == 0 {
|
||||
if err != nil || len(mx) == 0 {
|
||||
err = core.MalformedRequestError(fmt.Sprintf("No MX record for domain %s", domain))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func validateContacts(contacts []core.AcmeURL) (err error) {
|
||||
for _, contact := range contacts {
|
||||
switch contact.Scheme {
|
||||
case "tel":
|
||||
continue
|
||||
case "mailto":
|
||||
err = validateEmail(contact.Opaque)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
err = core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type certificateRequestEvent struct {
|
||||
ID string `json:",omitempty"`
|
||||
Requester int64 `json:",omitempty"`
|
||||
|
|
@ -98,24 +113,16 @@ func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration) (re
|
|||
}
|
||||
reg.MergeUpdate(init)
|
||||
|
||||
for _, contact := range reg.Contact {
|
||||
switch contact.Scheme {
|
||||
case "tel":
|
||||
continue
|
||||
case "mailto":
|
||||
err = validateEmail(contact.Opaque)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
default:
|
||||
err = core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme))
|
||||
return
|
||||
}
|
||||
err = validateContacts(reg.Contact)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Store the authorization object, then return it
|
||||
reg, err = ra.SA.NewRegistration(reg)
|
||||
if err != nil {
|
||||
// InternalServerError since the user-data was validated before being
|
||||
// passed to the SA.
|
||||
err = core.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
|
|
@ -124,7 +131,7 @@ func (ra *RegistrationAuthorityImpl) NewRegistration(init core.Registration) (re
|
|||
|
||||
func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization, regID int64) (authz core.Authorization, err error) {
|
||||
if regID <= 0 {
|
||||
err = core.InternalServerError("Invalid registration ID")
|
||||
err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID))
|
||||
return authz, err
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +169,9 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
|
|||
// Get a pending Auth first so we can get our ID back, then update with challenges
|
||||
authz, err = ra.SA.NewPendingAuthorization(authz)
|
||||
if err != nil {
|
||||
err = core.InternalServerError(err.Error())
|
||||
// InternalServerError since the user-data was validated before being
|
||||
// passed to the SA.
|
||||
err = core.InternalServerError(fmt.Sprintf("Invalid authorization request: %s", err))
|
||||
return authz, err
|
||||
}
|
||||
|
||||
|
|
@ -173,6 +182,8 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
|
|||
challenges[i].URI = core.AcmeURL(*challengeURI)
|
||||
|
||||
if !challenges[i].IsSane(false) {
|
||||
// InternalServerError because we generated these challenges, they should
|
||||
// be OK.
|
||||
err = core.InternalServerError(fmt.Sprintf("Challenge didn't pass sanity check: %+v", challenges[i]))
|
||||
return authz, err
|
||||
}
|
||||
|
|
@ -184,6 +195,8 @@ func (ra *RegistrationAuthorityImpl) NewAuthorization(request core.Authorization
|
|||
// Store the authorization object, then return it
|
||||
err = ra.SA.UpdatePendingAuthorization(authz)
|
||||
if err != nil {
|
||||
// InternalServerError because we created the authorization just above,
|
||||
// and adding Sane challenges should not break it.
|
||||
err = core.InternalServerError(err.Error())
|
||||
}
|
||||
return authz, err
|
||||
|
|
@ -211,7 +224,7 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
|
|||
}()
|
||||
|
||||
if regID <= 0 {
|
||||
err = core.InternalServerError("Invalid registration ID")
|
||||
err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID))
|
||||
return emptyCert, err
|
||||
}
|
||||
|
||||
|
|
@ -312,7 +325,10 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
|
|||
|
||||
// Create the certificate and log the result
|
||||
if cert, err = ra.CA.IssueCertificate(*csr, regID, earliestExpiry); err != nil {
|
||||
err = core.InternalServerError(err.Error())
|
||||
// While this could be InternalServerError for certain conditions, most
|
||||
// of the failure reasons (such as GoodKey failing) are caused by malformed
|
||||
// requests.
|
||||
err = core.MalformedRequestError(err.Error())
|
||||
logEvent.Error = err.Error()
|
||||
return emptyCert, err
|
||||
}
|
||||
|
|
@ -325,6 +341,8 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
|
|||
|
||||
parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER))
|
||||
if err != nil {
|
||||
// InternalServerError because the certificate from the CA should be
|
||||
// parseable.
|
||||
err = core.InternalServerError(err.Error())
|
||||
logEvent.Error = err.Error()
|
||||
return emptyCert, err
|
||||
|
|
@ -342,10 +360,18 @@ func (ra *RegistrationAuthorityImpl) NewCertificate(req core.CertificateRequest,
|
|||
|
||||
func (ra *RegistrationAuthorityImpl) UpdateRegistration(base core.Registration, update core.Registration) (reg core.Registration, err error) {
|
||||
base.MergeUpdate(update)
|
||||
|
||||
err = validateContacts(base.Contact)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
reg = base
|
||||
err = ra.SA.UpdateRegistration(base)
|
||||
if err != nil {
|
||||
err = core.InternalServerError(err.Error())
|
||||
// InternalServerError since the user-data was validated before being
|
||||
// passed to the SA.
|
||||
err = core.InternalServerError(fmt.Sprintf("Could not update registration: %s", err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -354,14 +380,16 @@ func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization
|
|||
// Copy information over that the client is allowed to supply
|
||||
authz = base
|
||||
if challengeIndex >= len(authz.Challenges) {
|
||||
err = core.MalformedRequestError("Invalid challenge index")
|
||||
err = core.MalformedRequestError(fmt.Sprintf("Invalid challenge index: %d", challengeIndex))
|
||||
return
|
||||
}
|
||||
authz.Challenges[challengeIndex] = authz.Challenges[challengeIndex].MergeResponse(response)
|
||||
|
||||
// Store the updated version
|
||||
if err = ra.SA.UpdatePendingAuthorization(authz); err != nil {
|
||||
err = core.InternalServerError(err.Error())
|
||||
// This can pretty much only happen when the client corrupts the Challenge
|
||||
// data.
|
||||
err = core.MalformedRequestError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,48 @@ func assertAuthzEqual(t *testing.T, a1, a2 core.Authorization) {
|
|||
// Not testing: Challenges
|
||||
}
|
||||
|
||||
func TestValidateContacts(t *testing.T) {
|
||||
tel, _ := url.Parse("tel:")
|
||||
ansible, _ := url.Parse("ansible:earth.sol.milkyway.laniakea/letsencrypt")
|
||||
validEmail, _ := url.Parse("mailto:admin@email.com")
|
||||
invalidEmail, _ := url.Parse("mailto:admin@example.com")
|
||||
malformedEmail, _ := url.Parse("mailto:admin.com")
|
||||
|
||||
err := validateContacts([]core.AcmeURL{})
|
||||
test.AssertNotError(t, err, "No Contacts")
|
||||
|
||||
err = validateContacts([]core.AcmeURL{core.AcmeURL(*tel)})
|
||||
test.AssertNotError(t, err, "Simple Telephone")
|
||||
|
||||
err = validateContacts([]core.AcmeURL{core.AcmeURL(*validEmail)})
|
||||
test.AssertNotError(t, err, "Valid Email")
|
||||
|
||||
err = validateContacts([]core.AcmeURL{core.AcmeURL(*invalidEmail)})
|
||||
test.AssertError(t, err, "Invalid Email")
|
||||
|
||||
err = validateContacts([]core.AcmeURL{core.AcmeURL(*malformedEmail)})
|
||||
test.AssertError(t, err, "Malformed Email")
|
||||
|
||||
err = validateContacts([]core.AcmeURL{core.AcmeURL(*ansible)})
|
||||
test.AssertError(t, err, "Unknown scehme")
|
||||
}
|
||||
|
||||
func TestValidateEmail(t *testing.T) {
|
||||
err := validateEmail("an email`")
|
||||
test.AssertError(t, err, "Malformed")
|
||||
|
||||
err = validateEmail("a@not.a.domain")
|
||||
test.AssertError(t, err, "Cannot resolve")
|
||||
t.Logf("No Resolve: %s", err)
|
||||
|
||||
err = validateEmail("a@example.com")
|
||||
test.AssertError(t, err, "No MX Record")
|
||||
t.Logf("No MX: %s", err)
|
||||
|
||||
err = validateEmail("a@email.com")
|
||||
test.AssertNotError(t, err, "Valid")
|
||||
}
|
||||
|
||||
func TestNewRegistration(t *testing.T) {
|
||||
_, _, sa, ra := initAuthorities(t)
|
||||
mailto, _ := url.Parse("mailto:foo@letsencrypt.org")
|
||||
|
|
@ -455,7 +497,7 @@ func TestNewCertificate(t *testing.T) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
test.Assert(t, bytes.Compare(cert.DER, dbCert) == 0, "Certificates differ")
|
||||
test.Assert(t, bytes.Compare(cert.DER, dbCert.DER) == 0, "Certificates differ")
|
||||
|
||||
t.Log("DONE TestOnValidationUpdate")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import (
|
|||
// where ROLE covers:
|
||||
// * RegistrationAuthority
|
||||
// * ValidationAuthority
|
||||
// * CertficateAuthority
|
||||
// * CertificateAuthority
|
||||
// * StorageAuthority
|
||||
//
|
||||
// For each one of these, the are ${ROLE}Client and ${ROLE}Server
|
||||
|
|
@ -777,18 +777,34 @@ func NewStorageAuthorityServer(rpc RPCServer, impl core.StorageAuthority) error
|
|||
|
||||
rpc.Handle(MethodGetCertificate, func(req []byte) (response []byte, err error) {
|
||||
cert, err := impl.GetCertificate(string(req))
|
||||
if err == nil {
|
||||
response = []byte(cert)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
jsonResponse, err := json.Marshal(cert)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetCertificate, err, req)
|
||||
return
|
||||
}
|
||||
|
||||
return jsonResponse, nil
|
||||
})
|
||||
|
||||
rpc.Handle(MethodGetCertificateByShortSerial, func(req []byte) (response []byte, err error) {
|
||||
cert, err := impl.GetCertificateByShortSerial(string(req))
|
||||
if err == nil {
|
||||
response = []byte(cert)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
|
||||
jsonResponse, err := json.Marshal(cert)
|
||||
if err != nil {
|
||||
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
|
||||
errorCondition(MethodGetCertificateByShortSerial, err, req)
|
||||
return
|
||||
}
|
||||
|
||||
return jsonResponse, nil
|
||||
})
|
||||
|
||||
rpc.Handle(MethodGetCertificateStatus, func(req []byte) (response []byte, err error) {
|
||||
|
|
@ -910,13 +926,23 @@ func (cac StorageAuthorityClient) GetAuthorization(id string) (authz core.Author
|
|||
return
|
||||
}
|
||||
|
||||
func (cac StorageAuthorityClient) GetCertificate(id string) (cert []byte, err error) {
|
||||
cert, err = cac.rpc.DispatchSync(MethodGetCertificate, []byte(id))
|
||||
func (cac StorageAuthorityClient) GetCertificate(id string) (cert core.Certificate, err error) {
|
||||
jsonCert, err := cac.rpc.DispatchSync(MethodGetCertificate, []byte(id))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(jsonCert, &cert)
|
||||
return
|
||||
}
|
||||
|
||||
func (cac StorageAuthorityClient) GetCertificateByShortSerial(id string) (cert []byte, err error) {
|
||||
cert, err = cac.rpc.DispatchSync(MethodGetCertificateByShortSerial, []byte(id))
|
||||
func (cac StorageAuthorityClient) GetCertificateByShortSerial(id string) (cert core.Certificate, err error) {
|
||||
jsonCert, err := cac.rpc.DispatchSync(MethodGetCertificateByShortSerial, []byte(id))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(jsonCert, &cert)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -166,44 +166,40 @@ func (ssa *SQLStorageAuthority) GetAuthorization(id string) (authz core.Authoriz
|
|||
// serial number and returns the first certificate whose full serial number is
|
||||
// lexically greater than that id. This allows clients to query on the known
|
||||
// sequential half of our serial numbers to enumerate all certificates.
|
||||
func (ssa *SQLStorageAuthority) GetCertificateByShortSerial(shortSerial string) (cert []byte, err error) {
|
||||
func (ssa *SQLStorageAuthority) GetCertificateByShortSerial(shortSerial string) (cert core.Certificate, err error) {
|
||||
if len(shortSerial) != 16 {
|
||||
err = errors.New("Invalid certificate short serial " + shortSerial)
|
||||
return
|
||||
}
|
||||
|
||||
var certificate core.Certificate
|
||||
err = ssa.dbMap.SelectOne(&certificate, "SELECT * FROM certificates WHERE serial LIKE :shortSerial",
|
||||
err = ssa.dbMap.SelectOne(&cert, "SELECT * FROM certificates WHERE serial LIKE :shortSerial",
|
||||
map[string]interface{}{"shortSerial": shortSerial + "%"})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return certificate.DER, nil
|
||||
return
|
||||
}
|
||||
|
||||
// GetCertificate takes a serial number and returns the corresponding
|
||||
// certificate, or error if it does not exist.
|
||||
func (ssa *SQLStorageAuthority) GetCertificate(serial string) ([]byte, error) {
|
||||
func (ssa *SQLStorageAuthority) GetCertificate(serial string) (core.Certificate, error) {
|
||||
if len(serial) != 32 {
|
||||
err := fmt.Errorf("Invalid certificate serial %s", serial)
|
||||
return nil, err
|
||||
return core.Certificate{}, err
|
||||
}
|
||||
|
||||
certObj, err := ssa.dbMap.Get(core.Certificate{}, serial)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return core.Certificate{}, err
|
||||
}
|
||||
if certObj == nil {
|
||||
ssa.log.Debug(fmt.Sprintf("Nil cert for %s", serial))
|
||||
return nil, fmt.Errorf("Certificate does not exist for %s", serial)
|
||||
return core.Certificate{}, fmt.Errorf("Certificate does not exist for %s", serial)
|
||||
}
|
||||
|
||||
cert, ok := certObj.(*core.Certificate)
|
||||
certPtr, ok := certObj.(*core.Certificate)
|
||||
if !ok {
|
||||
ssa.log.Debug("Failed to convert cert")
|
||||
return nil, fmt.Errorf("Error converting certificate response for %s", serial)
|
||||
return core.Certificate{}, fmt.Errorf("Error converting certificate response for %s", serial)
|
||||
}
|
||||
return cert.DER, err
|
||||
return *certPtr, err
|
||||
}
|
||||
|
||||
// GetCertificateStatus takes a hexadecimal string representing the full 128-bit serial
|
||||
|
|
|
|||
|
|
@ -143,13 +143,13 @@ func TestAddCertificate(t *testing.T) {
|
|||
test.AssertEquals(t, digest, "qWoItDZmR4P9eFbeYgXXP3SR4ApnkQj8x4LsB_ORKBo")
|
||||
|
||||
// Example cert serial is 0x21bd4, so a prefix of all zeroes should fetch it.
|
||||
retrievedDER, err := sa.GetCertificateByShortSerial("0000000000000000")
|
||||
retrievedCert, err := sa.GetCertificateByShortSerial("0000000000000000")
|
||||
test.AssertNotError(t, err, "Couldn't get www.eff.org.der by short serial")
|
||||
test.AssertByteEquals(t, certDER, retrievedDER)
|
||||
test.AssertByteEquals(t, certDER, retrievedCert.DER)
|
||||
|
||||
retrievedDER, err = sa.GetCertificate("00000000000000000000000000021bd4")
|
||||
retrievedCert, err = sa.GetCertificate("00000000000000000000000000021bd4")
|
||||
test.AssertNotError(t, err, "Couldn't get www.eff.org.der by full serial")
|
||||
test.AssertByteEquals(t, certDER, retrievedDER)
|
||||
test.AssertByteEquals(t, certDER, retrievedCert.DER)
|
||||
|
||||
certificateStatus, err := sa.GetCertificateStatus("00000000000000000000000000021bd4")
|
||||
test.AssertNotError(t, err, "Couldn't get status for www.eff.org.der")
|
||||
|
|
@ -166,13 +166,13 @@ func TestAddCertificate(t *testing.T) {
|
|||
test.AssertEquals(t, digest2, "CMVYqWzyqUW7pfBF2CxL0Uk6I0Upsk7p4EWSnd_vYx4")
|
||||
|
||||
// Example cert serial is 0x21bd4, so a prefix of all zeroes should fetch it.
|
||||
retrievedDER2, err := sa.GetCertificateByShortSerial("ff00000000000002")
|
||||
retrievedCert2, err := sa.GetCertificateByShortSerial("ff00000000000002")
|
||||
test.AssertNotError(t, err, "Couldn't get test-cert.der")
|
||||
test.AssertByteEquals(t, certDER2, retrievedDER2)
|
||||
test.AssertByteEquals(t, certDER2, retrievedCert2.DER)
|
||||
|
||||
retrievedDER2, err = sa.GetCertificate("ff00000000000002238054509817da5a")
|
||||
retrievedCert2, err = sa.GetCertificate("ff00000000000002238054509817da5a")
|
||||
test.AssertNotError(t, err, "Couldn't get test-cert.der")
|
||||
test.AssertByteEquals(t, certDER2, retrievedDER2)
|
||||
test.AssertByteEquals(t, certDER2, retrievedCert2.DER)
|
||||
|
||||
certificateStatus2, err := sa.GetCertificateStatus("ff00000000000002238054509817da5a")
|
||||
test.AssertNotError(t, err, "Couldn't get status for test-cert.der")
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ func (tc BoulderTypeConverter) ToDb(val interface{}) (interface{}, error) {
|
|||
return string(t), nil
|
||||
case core.OCSPStatus:
|
||||
return string(t), nil
|
||||
case core.JsonBuffer:
|
||||
return []byte(t), nil
|
||||
default:
|
||||
return val, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC6DCCAdCgAwIBAgICALIwDQYJKoZIhvcNAQELBQAwDjEMMAoGA1UEAwwDMTc4
|
||||
MB4XDTE1MDYxMzAwMTY1OFoXDTE2MDYxMjAwMTY1OFowDjEMMAoGA1UEAwwDMTc4
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmqs7nue5oFxKBk2WaFZJ
|
||||
Ama2nm1oFyPIq19gYEAdQN4mWvaJ8RjzHFkDMYUrlIrGxCYuFJDHFUk9dh19Na1M
|
||||
IY+NVLgcSbyNcOML3bLbLEwGmvXPbbEOflBA9mxUS9TLMgXW5ghf/qbt4vmSGKlo
|
||||
Iim41QXt55QFW6O+84s8Kd2OE6df0wTsEwLhZB3j5pDU+t7j5vTMv4Tc7EptaPkO
|
||||
dfQn+68viUJjlYM/4yIBVRhWCdexFdylCKVLg0obsghQEwULKYCUjdg6F0VJUI11
|
||||
5DU49tzscXU/3FS3CyY8rchunuYszBNkdmgpAwViHNWuP7ESdEd/emrj1xuioSe6
|
||||
PwIDAQABo1AwTjAdBgNVHQ4EFgQUEaQm2CFKX3v9tNF3LLRNqd5mGcMwHwYDVR0j
|
||||
BBgwFoAUEaQm2CFKX3v9tNF3LLRNqd5mGcMwDAYDVR0TBAUwAwEB/zANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEAdTi8Mt6JwfXPJU6ILNIXlySl01s7pfNf8Qz43k7AaZSJeI2A
|
||||
blM6ilFwbXpWls64XKFQRYfsQ9+wPA044pF1zR05PSI8PJwzIVAjW34myJnbsywb
|
||||
Yc1eQXlz0Di7R+w9HRkpVHG2CgnIBGJFa1H7p0FG9tyI7SaJ/Qri5BRJhnu2gYjx
|
||||
B+JV3ol+0oYYMhVVaGXwHpyjelsEiWaIFoO3o0YxfW19NM90QQnJ3BGX7ibJSxAr
|
||||
Lwbh8DWnWi4X3MdIPG88BKoavcXlJ/pyW2PvarUe31xVBNbyDlcZvrTZ8PXVw7TA
|
||||
lumboAhMDLhYNBWrJTJe5LOiapEJaOBNN/ZMFQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCaqzue57mgXEoG
|
||||
TZZoVkkCZraebWgXI8irX2BgQB1A3iZa9onxGPMcWQMxhSuUisbEJi4UkMcVST12
|
||||
HX01rUwhj41UuBxJvI1w4wvdstssTAaa9c9tsQ5+UED2bFRL1MsyBdbmCF/+pu3i
|
||||
+ZIYqWgiKbjVBe3nlAVbo77zizwp3Y4Tp1/TBOwTAuFkHePmkNT63uPm9My/hNzs
|
||||
Sm1o+Q519Cf7ry+JQmOVgz/jIgFVGFYJ17EV3KUIpUuDShuyCFATBQspgJSN2DoX
|
||||
RUlQjXXkNTj23OxxdT/cVLcLJjytyG6e5izME2R2aCkDBWIc1a4/sRJ0R396auPX
|
||||
G6KhJ7o/AgMBAAECggEAC7GkmVgVzc0Mf7uAArV7YaYYapQFCbLX6jUU2VIfpBbn
|
||||
uXroZQUo5FzKhAT4jYuMiaoFU+K6Wp6l+fcyz0sh9WugGOaupNiPrRhNfl6WeZvp
|
||||
5+9r1nRLjztMHhWErhMRpd+RJuU9NMi0NbP+2sR8LhEPe3OuUBL98LbJqio9y0Bp
|
||||
8+JxmATL7vTvORMMamt80bDRGLBzoGySWZ0lEWwTuv8RjiCqO85YmHd9BmnTpOUn
|
||||
siYfEDZ9t+EF6NgJaISMLmcbzxZI5+aPIvfc1TwzDA96LUccGwvAR4qZ/+eYsG2I
|
||||
Iwn1wMMSsvFWeq7AccKL/povPg1Iud0wzkLLZmMjGQKBgQDLRUtENxbVH/T4xw8W
|
||||
tdgfzddQWZmVPtQXHAt2/zmrgJ3DKu7HOUajCGGWdLnoiFrIO2LsQYpP1XUA4hG1
|
||||
vzLDBng6SHDqZdGfd8eFaHesafr/FG4zkk+GBIs+P8GzHs2/znpEiqLnPbWrrB3t
|
||||
2/zBIXluZSytGt1ysC+TZZFwhQKBgQDCymmryD0JRV0M1IgwXOZrO+2MWDdliujx
|
||||
uBfD6DdLCJ5wHrPiySjVvl0njPLDQcWigigJD8Jl0SRQ8JSbceFzEGjzEj3NR2oB
|
||||
aLn3Gf3nORo7tJdCZVQn7QcHT+HzAWffm6qjqKzPXjRAEFFcW48Bnw+BU/JuZNOe
|
||||
v7dTuyv88wKBgFROGAphwsF/8I0hmht0Lf/60ltL3gvtM++lvQeMkTGVNVlVvBS6
|
||||
p5ZEipzpKpXLv8MeBkgwYpn70PwdxvSXKQmD7GdX1iURN6CpAAJPspq6ldQneBFB
|
||||
lGPkDJAzxzVwCCuOCl3VFf1MNcXOq9cUDz9Wj9N+eMoOw1umwQSj8m81AoGAP/li
|
||||
gzycbzMMwG383IVmV8my1ukSKJNatiiUBY96uXX3MzOiONWAR9LhnV+5S0+KrTi6
|
||||
FV/LpMzvdHXPGM5qEPROw6Y2DflqY1QV34X10b77UqiZFQFahlJegJRHzRulFdd2
|
||||
T5HST7jMyE2TqxWW/h1TZlI/yOnsZrLobuOGKukCgYAGk/TRPSOWEkH3rL7cDJFp
|
||||
ql4d33iuW9b3dMvQgkDW8H2kj3QA5os9dtSFLA/fWubULXOPpOsA7Ny7okBxsUBW
|
||||
tn4ER+HjUHogGir5d5cBBpvi4xM2/B4KaZnX8IHYhFcT42eb1oYmpfz5GcRyqzTX
|
||||
OoetYnUS5t4QuAAMadjtig==
|
||||
-----END PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC6DCCAdCgAwIBAgICAO4wDQYJKoZIhvcNAQELBQAwDjEMMAoGA1UEAwwDMjM4
|
||||
MB4XDTE1MDYxMzAwMTU1NVoXDTE2MDYxMjAwMTU1NVowDjEMMAoGA1UEAwwDMjM4
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvP9z1YFDa1WD9hVI9W3K
|
||||
lWQmUGfLW35x6xkgDm8o3OTWR2QoxjXratacKhm2VevV22QjCBvHXeHx3fxSp5w/
|
||||
p4CH+Ul76wCq3+WAPidO42YCP7SZdqYUR4GHKQ/oOyistRAKEamg4aPAbIs7l1Kn
|
||||
T5YHFdSzCWpe6F2+ceoluvKEn6vFVloXKghaeEyTDKnnJKs3/04TdtZjVM5OObvQ
|
||||
CGFlQlysDJxWahtVM93gylB8WYgyiekDAx1I3lCd3Vv0hF+x04xT3fwVRzmaKNzT
|
||||
wN+znae643Qfg2oSSLV066K2WYepgzqKwv3IUdrLbes331AMs+FbdxHanMrOU1i+
|
||||
OQIDAQABo1AwTjAdBgNVHQ4EFgQUjog7s8eJhAvSKMvu6xHZxPnnjsgwHwYDVR0j
|
||||
BBgwFoAUjog7s8eJhAvSKMvu6xHZxPnnjsgwDAYDVR0TBAUwAwEB/zANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEAIugSn0o0HQMLy02inFZDso4PiRfoqahsT60oIMmWhF3nY3Jq
|
||||
GZmkozKGnvyNDeKPlf6TV04VLq6dRg7+yQDL6LCiq2wcGZ+8feMLjyRFwZDSjAJe
|
||||
sAMhNq9OQdGNfUV1iZF0SUzqrT68BCT0JTtuDpwlMcmH1O+jFf2HCzROLLBdRC3w
|
||||
tJGiA6DH2TqVnucql6sMrnxPVEB+uVfFaKNc9YzwDCp8dSmBbCz7wRmLobGKcnbQ
|
||||
lByD5j4dxYkFvJ6n/YX1HKJzwqTWhLQaxvFW7YvnPWepEiXiB6BaIsRgyK7Qa8EW
|
||||
3jL5yiB1Dd8OQ7aV7+PNwBNXHd3J1Vie2k52KA==
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8/3PVgUNrVYP2
|
||||
FUj1bcqVZCZQZ8tbfnHrGSAObyjc5NZHZCjGNetq1pwqGbZV69XbZCMIG8dd4fHd
|
||||
/FKnnD+ngIf5SXvrAKrf5YA+J07jZgI/tJl2phRHgYcpD+g7KKy1EAoRqaDho8Bs
|
||||
izuXUqdPlgcV1LMJal7oXb5x6iW68oSfq8VWWhcqCFp4TJMMqeckqzf/ThN21mNU
|
||||
zk45u9AIYWVCXKwMnFZqG1Uz3eDKUHxZiDKJ6QMDHUjeUJ3dW/SEX7HTjFPd/BVH
|
||||
OZoo3NPA37Odp7rjdB+DahJItXTrorZZh6mDOorC/chR2stt6zffUAyz4Vt3Edqc
|
||||
ys5TWL45AgMBAAECggEAc1PSJCt/r2R8ZNJyNclsQCLfulrL3aXX7+TiCczM+5Xs
|
||||
J543v1Oxtv0ESDBuchm54ulE8zK4QlKYm6PX8A1JTnYBAx5TLoC2xG8wBT1JRzu9
|
||||
DZCvwJXxc/zXNDhPtqHIWahS7Jo84NNinRmNIHbAP7FF241yPsGY7mQdzTdbFKrR
|
||||
JH0l7VPCY4OG+CjxUJqoNuwkfrNh0hRh02IHU/rFlgR2Q7JP0XBwuufW1M6j7fYM
|
||||
7PGZRA+6Ry72UcaCEVuOtGlz3wLrFq6CGTGWlUehQqch+nrTri0jMSH4Bd83mLz2
|
||||
8+X0y/EONQlirbHbJxXq+mLASHrp3KCtdpCiLKcX8QKBgQDr+TNqLa7PIOhlw29A
|
||||
RftunKwEdsi9uAg3jFSpHC/jLxR4/fUiz2XZrAfHNxn7mOK72V/9pj9zshLnxeSm
|
||||
jEelEB2bABX8RhD38SUxoHoiWmqpPVOtBSXvMSQEO0F/1hGlxndHwe9mE2Zyq3eV
|
||||
9MoJVeExkCP3Bxk9tjZfj4WC9QKBgQDNCab2WjLy7T9Bfmh2RmWXckzUMphYCLpX
|
||||
CGG2O5nH2zOPAOxUpyLFDq3/WkzPnCdWOveI/LlZmkcjdslWp3tizk5kE1zgaFbO
|
||||
s+7o/cYVrU5J3+kIq563ba7/xZ7wpfkg58milUWStpjQrB0H5tSlUEoC7fJ/GjHd
|
||||
5j1raKQrtQKBgF9elSgJlIgD/cj7JqBsaET5LxCSzWjX0wJYRfMfAD+qTHTl9sf9
|
||||
2GUUAQTDwU2NKb3QCdqi8SwaQUfJFDM3qNEOZVi6vSf7TWpX3Ldk61etAUSrE4Fu
|
||||
/jjgvHS1WjCHXRSJ1LV8rPutRY98u1Uw3OLPAbedUNvK06m8VddjUwttAoGAAmca
|
||||
jciA0Ff3Zc0VbE1m419zhwkQv/daN6rhekE4jB8Fe6eHHXbX8Xc6ksN8IvKxg1Et
|
||||
lW1gvqwQKVo7Acj0qTPBt2qCrB6M5d817YULzTU6taLqGC/qrDuc0WJ/elJ3mOse
|
||||
cclOB2ocYFWkAXOzCjzmoSIotVSZQQBxt9CCHAECgYEA01w8tKVCG2ucbC1GoCl0
|
||||
t2MRmLqiRqRrn53fJ6j56fDbdLmnRAaaD1slZ0jpLk7JoDKGmNG2Rl9UXuydPaNZ
|
||||
8h1Lu+CnhG50uOF3A/OIXsBiRsAgI2ez4/Jb+lNe3l3UcPV5gyGejAiymqRigbkn
|
||||
bcixOm4jdOWV5Bpfv65AivQ=
|
||||
-----END PRIVATE KEY-----
|
||||
|
|
@ -71,8 +71,18 @@ func statusCodeFromError(err interface{}) int {
|
|||
switch err.(type) {
|
||||
case core.MalformedRequestError:
|
||||
return http.StatusBadRequest
|
||||
case core.NotSupportedError:
|
||||
return http.StatusNotImplemented
|
||||
case core.SyntaxError:
|
||||
return http.StatusBadRequest
|
||||
case core.UnauthorizedError:
|
||||
return http.StatusForbidden
|
||||
case core.NotFoundError:
|
||||
return http.StatusNotFound
|
||||
case core.SignatureValidationError:
|
||||
return http.StatusPreconditionFailed
|
||||
case core.InternalServerError:
|
||||
return http.StatusInternalServerError
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
|
@ -208,11 +218,16 @@ func (wfe *WebFrontEndImpl) verifyPOST(request *http.Request, regCheck bool) ([]
|
|||
return nil, nil, reg, errors.New("JWS has invalid anti-replay nonce")
|
||||
}
|
||||
|
||||
if regCheck {
|
||||
// Check that the key is assosiated with an actual account
|
||||
reg, err = wfe.SA.GetRegistrationByKey(*key)
|
||||
if err != nil {
|
||||
reg, err = wfe.SA.GetRegistrationByKey(*key)
|
||||
if err != nil {
|
||||
// If we are requiring a valid registration, any failure to look up the
|
||||
// registration is an overall failure to verify.
|
||||
if regCheck {
|
||||
return nil, nil, reg, err
|
||||
} else {
|
||||
// Otherwise we just return an empty registration. The caller is expected
|
||||
// to use the returned key instead.
|
||||
reg = core.Registration{}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -306,6 +321,7 @@ func (wfe *WebFrontEndImpl) NewRegistration(response http.ResponseWriter, reques
|
|||
regURL := fmt.Sprintf("%s%d", wfe.RegBase, id)
|
||||
responseBody, err := json.Marshal(reg)
|
||||
if err != nil {
|
||||
// StatusInternalServerError because we just created this registration, it should be OK.
|
||||
wfe.sendError(response, "Error marshaling registration", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -369,6 +385,7 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
|
|||
authz.RegistrationID = 0
|
||||
responseBody, err := json.Marshal(authz)
|
||||
if err != nil {
|
||||
// StatusInternalServerError because we generated the authz, it should be OK
|
||||
wfe.sendError(response, "Error marshaling authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -395,7 +412,7 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
|
|||
|
||||
// We don't ask verifyPOST to verify there is a correponding registration,
|
||||
// because anyone with the right private key can revoke a certificate.
|
||||
body, requestKey, _, err := wfe.verifyPOST(request, false)
|
||||
body, requestKey, registration, err := wfe.verifyPOST(request, false)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "Unable to read/verify body", err, http.StatusBadRequest)
|
||||
return
|
||||
|
|
@ -418,20 +435,21 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
|
|||
}
|
||||
|
||||
serial := core.SerialToString(providedCert.SerialNumber)
|
||||
certDER, err := wfe.SA.GetCertificate(serial)
|
||||
if err != nil || !bytes.Equal(certDER, revokeRequest.CertificateDER) {
|
||||
cert, err := wfe.SA.GetCertificate(serial)
|
||||
if err != nil || !bytes.Equal(cert.DER, revokeRequest.CertificateDER) {
|
||||
wfe.sendError(response, "No such certificate", err, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
parsedCertificate, err := x509.ParseCertificate(certDER)
|
||||
parsedCertificate, err := x509.ParseCertificate(cert.DER)
|
||||
if err != nil {
|
||||
// InternalServerError because this is a failure to decode from our DB.
|
||||
wfe.sendError(response, "Invalid certificate", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
certStatus, err := wfe.SA.GetCertificateStatus(serial)
|
||||
if err != nil {
|
||||
wfe.sendError(response, "No such certificate", err, http.StatusNotFound)
|
||||
wfe.sendError(response, "Certificate status not yet available", err, http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -440,9 +458,9 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
|
|||
return
|
||||
}
|
||||
|
||||
// TODO: Implement other methods of validating revocation, e.g. through
|
||||
// authorizations on account.
|
||||
if !core.KeyDigestEquals(requestKey, parsedCertificate.PublicKey) {
|
||||
// TODO: Implement method of revocation by authorizations on account.
|
||||
if !(core.KeyDigestEquals(requestKey, parsedCertificate.PublicKey) ||
|
||||
registration.ID == cert.RegistrationID) {
|
||||
wfe.log.Debug("Key mismatch for revoke")
|
||||
wfe.sendError(response,
|
||||
"Revocation request must be signed by private key of cert to be revoked",
|
||||
|
|
@ -536,7 +554,7 @@ func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request
|
|||
wfe.Stats.Inc("Certificates", 1, 1.0)
|
||||
}
|
||||
|
||||
func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.ResponseWriter, request *http.Request) {
|
||||
func (wfe *WebFrontEndImpl) challenge(authz core.Authorization, response http.ResponseWriter, request *http.Request) {
|
||||
wfe.sendStandardHeaders(response)
|
||||
|
||||
if request.Method != "GET" && request.Method != "POST" {
|
||||
|
|
@ -572,6 +590,8 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
|
|||
challenge := authz.Challenges[challengeIndex]
|
||||
jsonReply, err := json.Marshal(challenge)
|
||||
if err != nil {
|
||||
// InternalServerError because this is a failure to decode data passed in
|
||||
// by the caller, which got it from the DB.
|
||||
wfe.sendError(response, "Failed to marshal challenge", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -630,6 +650,7 @@ func (wfe *WebFrontEndImpl) Challenge(authz core.Authorization, response http.Re
|
|||
// assumption: UpdateAuthorization does not modify order of challenges
|
||||
jsonReply, err := json.Marshal(challenge)
|
||||
if err != nil {
|
||||
// StatusInternalServerError because we made the challenges, they should be OK
|
||||
wfe.sendError(response, "Failed to marshal challenge", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -713,6 +734,7 @@ func (wfe *WebFrontEndImpl) Registration(response http.ResponseWriter, request *
|
|||
|
||||
jsonReply, err := json.Marshal(updatedReg)
|
||||
if err != nil {
|
||||
// StatusInternalServerError because we just generated the reg, it should be OK
|
||||
wfe.sendError(response, "Failed to marshal registration", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -742,7 +764,7 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request
|
|||
|
||||
// If there is a fragment, then this is actually a request to a challenge URI
|
||||
if len(request.URL.RawQuery) != 0 {
|
||||
wfe.Challenge(authz, response, request)
|
||||
wfe.challenge(authz, response, request)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -759,6 +781,7 @@ func (wfe *WebFrontEndImpl) Authorization(response http.ResponseWriter, request
|
|||
|
||||
jsonReply, err := json.Marshal(authz)
|
||||
if err != nil {
|
||||
// InternalServerError because this is a failure to decode from our DB.
|
||||
wfe.sendError(response, "Failed to marshal authz", err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
|
@ -806,7 +829,7 @@ func (wfe *WebFrontEndImpl) Certificate(response http.ResponseWriter, request *h
|
|||
cert, err := wfe.SA.GetCertificateByShortSerial(serial)
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "gorp: multiple rows returned") {
|
||||
wfe.sendError(response, "Multiple certificates with same short serial", err, http.StatusInternalServerError)
|
||||
wfe.sendError(response, "Multiple certificates with same short serial", err, http.StatusConflict)
|
||||
} else {
|
||||
wfe.sendError(response, "Not found", err, http.StatusNotFound)
|
||||
}
|
||||
|
|
@ -817,7 +840,7 @@ func (wfe *WebFrontEndImpl) Certificate(response http.ResponseWriter, request *h
|
|||
response.Header().Set("Content-Type", "application/pkix-cert")
|
||||
response.Header().Add("Link", link(IssuerPath, "up"))
|
||||
response.WriteHeader(http.StatusOK)
|
||||
if _, err = response.Write(cert); err != nil {
|
||||
if _, err = response.Write(cert.DER); err != nil {
|
||||
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
|
@ -170,16 +171,44 @@ func (sa *MockSA) GetAuthorization(id string) (core.Authorization, error) {
|
|||
return core.Authorization{}, nil
|
||||
}
|
||||
|
||||
func (sa *MockSA) GetCertificate(string) ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
func (sa *MockSA) GetCertificate(serial string) (core.Certificate, error) {
|
||||
// Serial ee == 238.crt
|
||||
if serial == "000000000000000000000000000000ee" {
|
||||
certPemBytes, _ := ioutil.ReadFile("test/238.crt")
|
||||
certBlock, _ := pem.Decode(certPemBytes)
|
||||
return core.Certificate{
|
||||
RegistrationID: 1,
|
||||
DER: certBlock.Bytes,
|
||||
}, nil
|
||||
} else if serial == "000000000000000000000000000000b2" {
|
||||
certPemBytes, _ := ioutil.ReadFile("test/178.crt")
|
||||
certBlock, _ := pem.Decode(certPemBytes)
|
||||
return core.Certificate{
|
||||
RegistrationID: 1,
|
||||
DER: certBlock.Bytes,
|
||||
}, nil
|
||||
} else {
|
||||
return core.Certificate{}, errors.New("No cert")
|
||||
}
|
||||
}
|
||||
|
||||
func (sa *MockSA) GetCertificateByShortSerial(string) ([]byte, error) {
|
||||
return []byte{}, nil
|
||||
func (sa *MockSA) GetCertificateByShortSerial(string) (core.Certificate, error) {
|
||||
return core.Certificate{}, nil
|
||||
}
|
||||
|
||||
func (sa *MockSA) GetCertificateStatus(string) (core.CertificateStatus, error) {
|
||||
return core.CertificateStatus{}, nil
|
||||
func (sa *MockSA) GetCertificateStatus(serial string) (core.CertificateStatus, error) {
|
||||
// Serial ee == 238.crt
|
||||
if serial == "000000000000000000000000000000ee" {
|
||||
return core.CertificateStatus{
|
||||
Status: core.OCSPStatusGood,
|
||||
}, nil
|
||||
} else if serial == "000000000000000000000000000000b2" {
|
||||
return core.CertificateStatus{
|
||||
Status: core.OCSPStatusRevoked,
|
||||
}, nil
|
||||
} else {
|
||||
return core.CertificateStatus{}, errors.New("No cert status")
|
||||
}
|
||||
}
|
||||
|
||||
func (sa *MockSA) AlreadyDeniedCSR([]string) (bool, error) {
|
||||
|
|
@ -521,7 +550,7 @@ func TestChallenge(t *testing.T) {
|
|||
RegistrationID: 1,
|
||||
}
|
||||
|
||||
wfe.Challenge(authz, responseWriter, &http.Request{
|
||||
wfe.challenge(authz, responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
URL: challengeURL,
|
||||
Body: makeBody(signRequest(t, "{}", &wfe.nonceService)),
|
||||
|
|
@ -665,6 +694,104 @@ func TestNewRegistration(t *testing.T) {
|
|||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Registration key is already in use\"}")
|
||||
}
|
||||
|
||||
// Valid revocation request for existing, non-revoked cert
|
||||
func TestRevokeCertificate(t *testing.T) {
|
||||
keyPemBytes, err := ioutil.ReadFile("test/238.key")
|
||||
test.AssertNotError(t, err, "Failed to load key")
|
||||
key, err := jose.LoadPrivateKey(keyPemBytes)
|
||||
test.AssertNotError(t, err, "Failed to load key")
|
||||
rsaKey, ok := key.(*rsa.PrivateKey)
|
||||
test.Assert(t, ok, "Couldn't load RSA key")
|
||||
signer, err := jose.NewSigner("RS256", rsaKey)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
|
||||
certPemBytes, err := ioutil.ReadFile("test/238.crt")
|
||||
test.AssertNotError(t, err, "Failed to load cert")
|
||||
certBlock, _ := pem.Decode(certPemBytes)
|
||||
test.Assert(t, certBlock != nil, "Failed to decode PEM")
|
||||
var revokeRequest struct {
|
||||
CertificateDER core.JsonBuffer `json:"certificate"`
|
||||
}
|
||||
revokeRequest.CertificateDER = certBlock.Bytes
|
||||
revokeRequestJSON, err := json.Marshal(revokeRequest)
|
||||
test.AssertNotError(t, err, "Failed to marshal request")
|
||||
|
||||
// POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON.
|
||||
wfe := setupWFE()
|
||||
|
||||
wfe.RA = &MockRegistrationAuthority{}
|
||||
wfe.SA = &MockSA{}
|
||||
wfe.Stats, _ = statsd.NewNoopClient()
|
||||
wfe.SubscriberAgreementURL = agreementURL
|
||||
responseWriter := httptest.NewRecorder()
|
||||
responseWriter.Body.Reset()
|
||||
result, _ := signer.Sign(revokeRequestJSON, wfe.nonceService.Nonce())
|
||||
wfe.RevokeCertificate(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody(result.FullSerialize()),
|
||||
})
|
||||
test.AssertEquals(t, responseWriter.Code, 200)
|
||||
test.AssertEquals(t, responseWriter.Body.String(), "")
|
||||
|
||||
// Try the revoke request again, signed by account key associated with cert.
|
||||
// Should also succeed.
|
||||
responseWriter.Body.Reset()
|
||||
test1JWK, err := jose.LoadPrivateKey([]byte(test1KeyPrivatePEM))
|
||||
test.AssertNotError(t, err, "Failed to load key")
|
||||
test1Key, ok := test1JWK.(*rsa.PrivateKey)
|
||||
test.Assert(t, ok, "Couldn't load RSA key")
|
||||
accountKeySigner, err := jose.NewSigner("RS256", test1Key)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
result, _ = accountKeySigner.Sign(revokeRequestJSON, wfe.nonceService.Nonce())
|
||||
wfe.RevokeCertificate(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody(result.FullSerialize()),
|
||||
})
|
||||
test.AssertEquals(t, responseWriter.Code, 200)
|
||||
test.AssertEquals(t, responseWriter.Body.String(), "")
|
||||
}
|
||||
|
||||
// Valid revocation request for already-revoked cert
|
||||
func TestRevokeCertificateAlreadyRevoked(t *testing.T) {
|
||||
keyPemBytes, err := ioutil.ReadFile("test/178.key")
|
||||
test.AssertNotError(t, err, "Failed to load key")
|
||||
key, err := jose.LoadPrivateKey(keyPemBytes)
|
||||
test.AssertNotError(t, err, "Failed to load key")
|
||||
rsaKey, ok := key.(*rsa.PrivateKey)
|
||||
test.Assert(t, ok, "Couldn't load RSA key")
|
||||
signer, err := jose.NewSigner("RS256", rsaKey)
|
||||
test.AssertNotError(t, err, "Failed to make signer")
|
||||
|
||||
certPemBytes, err := ioutil.ReadFile("test/178.crt")
|
||||
test.AssertNotError(t, err, "Failed to load cert")
|
||||
certBlock, _ := pem.Decode(certPemBytes)
|
||||
test.Assert(t, certBlock != nil, "Failed to decode PEM")
|
||||
var revokeRequest struct {
|
||||
CertificateDER core.JsonBuffer `json:"certificate"`
|
||||
}
|
||||
revokeRequest.CertificateDER = certBlock.Bytes
|
||||
revokeRequestJSON, err := json.Marshal(revokeRequest)
|
||||
test.AssertNotError(t, err, "Failed to marshal request")
|
||||
|
||||
// POST, Properly JWS-signed, but payload is "foo", not base64-encoded JSON.
|
||||
wfe := setupWFE()
|
||||
|
||||
wfe.RA = &MockRegistrationAuthority{}
|
||||
wfe.SA = &MockSA{}
|
||||
wfe.Stats, _ = statsd.NewNoopClient()
|
||||
wfe.SubscriberAgreementURL = agreementURL
|
||||
responseWriter := httptest.NewRecorder()
|
||||
responseWriter.Body.Reset()
|
||||
result, _ := signer.Sign(revokeRequestJSON, wfe.nonceService.Nonce())
|
||||
wfe.RevokeCertificate(responseWriter, &http.Request{
|
||||
Method: "POST",
|
||||
Body: makeBody(result.FullSerialize()),
|
||||
})
|
||||
test.AssertEquals(t, responseWriter.Code, 409)
|
||||
test.AssertEquals(t, responseWriter.Body.String(),
|
||||
"{\"type\":\"urn:acme:error:malformed\",\"detail\":\"Certificate already revoked\"}")
|
||||
}
|
||||
|
||||
func TestAuthorization(t *testing.T) {
|
||||
wfe := setupWFE()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue