Merge pull request #680 from letsencrypt/log-revoke

Log more about revocation process
This commit is contained in:
Roland Shoemaker 2015-08-27 22:34:27 -07:00
commit d3c8d8e409
10 changed files with 116 additions and 51 deletions

View File

@ -223,7 +223,7 @@ func (ca *CertificateAuthorityImpl) GenerateOCSP(xferObj core.OCSPSigningRequest
signRequest := ocsp.SignRequest{
Certificate: cert,
Status: xferObj.Status,
Reason: xferObj.Reason,
Reason: int(xferObj.Reason),
RevokedAt: xferObj.RevokedAt,
}
@ -232,7 +232,7 @@ 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) {
func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string, reasonCode core.RevocationCode) (err error) {
coreCert, err := ca.SA.GetCertificate(serial)
if err != nil {
// AUDIT[ Revocation Requests ] 4e85d791-09c0-4ab3-a837-d3d67e945134
@ -249,7 +249,7 @@ func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string, reasonCode
signRequest := ocsp.SignRequest{
Certificate: cert,
Status: string(core.OCSPStatusRevoked),
Reason: reasonCode,
Reason: int(reasonCode),
RevokedAt: time.Now(),
}
ocspResponse, err := ca.OCSPSigner.Sign(signRequest)

View File

@ -25,20 +25,6 @@ import (
"github.com/letsencrypt/boulder/sa"
)
var reasons = map[int]string{
0: "unspecified",
1: "keyCompromise",
2: "cACompromise",
3: "affiliationChanged",
4: "superseded",
5: "cessationOfOperation",
6: "certificateHold",
// 7 is unused
8: "removeFromCRL", // needed?
9: "privilegeWithdrawn",
10: "aAcompromise",
}
func loadConfig(c *cli.Context) (config cmd.Config, err error) {
configFileName := c.GlobalString("config")
configJSON, err := ioutil.ReadFile(configFileName)
@ -90,7 +76,7 @@ func addDeniedNames(tx *gorp.Transaction, names []string) (err error) {
return
}
func revokeBySerial(serial string, reasonCode int, deny bool, cac rpc.CertificateAuthorityClient, auditlogger *blog.AuditLogger, tx *gorp.Transaction) (err error) {
func revokeBySerial(serial string, reasonCode core.RevocationCode, deny bool, cac rpc.CertificateAuthorityClient, auditlogger *blog.AuditLogger, tx *gorp.Transaction) (err error) {
if reasonCode < 0 || reasonCode == 7 || reasonCode > 10 {
panic(fmt.Sprintf("Invalid reason code: %d", reasonCode))
}
@ -122,11 +108,11 @@ func revokeBySerial(serial string, reasonCode int, deny bool, cac rpc.Certificat
return
}
auditlogger.Info(fmt.Sprintf("Revoked certificate %s with reason '%s'", serial, reasons[reasonCode]))
auditlogger.Info(fmt.Sprintf("Revoked certificate %s with reason '%s'", serial, core.RevocationReasons[reasonCode]))
return
}
func revokeByReg(regID int64, reasonCode int, deny bool, cac rpc.CertificateAuthorityClient, auditlogger *blog.AuditLogger, tx *gorp.Transaction) (err error) {
func revokeByReg(regID int64, reasonCode core.RevocationCode, deny bool, cac rpc.CertificateAuthorityClient, auditlogger *blog.AuditLogger, tx *gorp.Transaction) (err error) {
var certs []core.Certificate
_, err = tx.Select(&certs, "SELECT serial FROM certificates WHERE registrationID = :regID", map[string]interface{}{"regID": regID})
if err != nil {
@ -182,7 +168,7 @@ func main() {
}
cmd.FailOnError(err, "Couldn't begin transaction")
err = revokeBySerial(serial, reasonCode, deny, cac, auditlogger, tx)
err = revokeBySerial(serial, core.RevocationCode(reasonCode), deny, cac, auditlogger, tx)
if err != nil {
tx.Rollback()
}
@ -218,7 +204,7 @@ func main() {
cmd.FailOnError(err, "Couldn't fetch registration")
}
err = revokeByReg(regID, reasonCode, deny, cac, auditlogger, tx)
err = revokeByReg(regID, core.RevocationCode(reasonCode), deny, cac, auditlogger, tx)
if err != nil {
tx.Rollback()
}
@ -232,14 +218,14 @@ func main() {
Name: "list-reasons",
Usage: "List all revocation reason codes",
Action: func(c *cli.Context) {
var codes []int
for k := range reasons {
var codes core.RevocationCodes
for k := range core.RevocationReasons {
codes = append(codes, k)
}
sort.Ints(codes)
sort.Sort(codes)
fmt.Printf("Revocation reason codes\n-----------------------\n\n")
for _, k := range codes {
fmt.Printf("%d: %s\n", k, reasons[k])
fmt.Printf("%d: %s\n", k, core.RevocationReasons[k])
}
},
},

View File

@ -71,7 +71,7 @@ type RegistrationAuthority interface {
UpdateAuthorization(Authorization, int, Challenge) (Authorization, error)
// [WebFrontEnd]
RevokeCertificate(x509.Certificate) error
RevokeCertificate(x509.Certificate, RevocationCode, *int64) error
// [ValidationAuthority]
OnValidationUpdate(Authorization) error
@ -88,7 +88,7 @@ type ValidationAuthority interface {
type CertificateAuthority interface {
// [RegistrationAuthority]
IssueCertificate(x509.CertificateRequest, int64, time.Time) (Certificate, error)
RevokeCertificate(string, int) error
RevokeCertificate(string, RevocationCode) error
GenerateOCSP(OCSPSigningRequest) ([]byte, error)
}
@ -118,7 +118,7 @@ type StorageAdder interface {
NewPendingAuthorization(Authorization) (Authorization, error)
UpdatePendingAuthorization(Authorization) error
FinalizeAuthorization(Authorization) error
MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode int) error
MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode RevocationCode) error
UpdateOCSP(serial string, ocspResponse []byte) error
AddCertificate([]byte, int64) (string, error)

View File

@ -597,7 +597,7 @@ type CertificateStatus struct {
// revokedReason: If status is 'revoked', this is the reason code for the
// revocation. Otherwise it is zero (which happens to be the reason
// code for 'unspecified').
RevokedReason int `db:"revokedReason"`
RevokedReason RevocationCode `db:"revokedReason"`
LastExpirationNagSent time.Time `db:"lastExpirationNagSent"`
@ -646,6 +646,39 @@ type DeniedCSR struct {
type OCSPSigningRequest struct {
CertDER []byte
Status string
Reason int
Reason RevocationCode
RevokedAt time.Time
}
// RevocationCode is used to specify a certificate revocation reason
type RevocationCode int
type RevocationCodes []RevocationCode
func (rc RevocationCodes) Len() int {
return len(rc)
}
func (rc RevocationCodes) Less(i, j int) bool {
return rc[i] < rc[j]
}
func (rc RevocationCodes) Swap(i, j int) {
rc[i], rc[j] = rc[j], rc[i]
}
// RevocationReasons provides a map from reason code to string explaining the
// code
var RevocationReasons = map[RevocationCode]string{
0: "unspecified",
1: "keyCompromise",
2: "cACompromise",
3: "affiliationChanged",
4: "superseded",
5: "cessationOfOperation",
6: "certificateHold",
// 7 is unused
8: "removeFromCRL", // needed?
9: "privilegeWithdrawn",
10: "aAcompromise",
}

View File

@ -381,17 +381,41 @@ func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization
}
// RevokeCertificate terminates trust in the certificate provided.
func (ra *RegistrationAuthorityImpl) RevokeCertificate(cert x509.Certificate) (err error) {
func (ra *RegistrationAuthorityImpl) RevokeCertificate(cert x509.Certificate, revocationCode core.RevocationCode, regID *int64) (err error) {
serialString := core.SerialToString(cert.SerialNumber)
err = ra.CA.RevokeCertificate(serialString, 0)
err = ra.CA.RevokeCertificate(serialString, revocationCode)
state := "Failure"
defer func() {
// AUDIT[ Revocation Requests ] 4e85d791-09c0-4ab3-a837-d3d67e945134
// Needed:
// Serial
// CN
// Revocation reason
// Error (if there was one)
revMsg := fmt.Sprintf(
"Revocation - State: %s, Serial: %s, CN: %s, DNS Names: %s, Reason: %s",
state,
serialString,
cert.Subject.CommonName,
cert.DNSNames,
core.RevocationReasons[revocationCode],
)
// Check regID is set, if not revocation came from the admin-revoker tool
if regID != nil {
revMsg = fmt.Sprintf("%s, Requested by registration ID: %d", revMsg, *regID)
} else {
revMsg = fmt.Sprintf("%s, Revoked using admin tool", revMsg)
}
ra.log.Audit(revMsg)
}()
// AUDIT[ Revocation Requests ] 4e85d791-09c0-4ab3-a837-d3d67e945134
if err != nil {
ra.log.Audit(fmt.Sprintf("Revocation error - %s - %s", serialString, err))
state = fmt.Sprintf("Failure -- %s", err)
return err
}
state = "Success"
ra.log.Audit(fmt.Sprintf("Revocation - %s", serialString))
return err
}

View File

@ -108,13 +108,13 @@ type addCertificateRequest struct {
type revokeCertificateRequest struct {
Serial string
ReasonCode int
ReasonCode core.RevocationCode
}
type markCertificateRevokedRequest struct {
Serial string
OCSPResponse []byte
ReasonCode int
ReasonCode core.RevocationCode
}
type caaRequest struct {
@ -272,14 +272,23 @@ func NewRegistrationAuthorityServer(rpc RPCServer, impl core.RegistrationAuthori
})
rpc.Handle(MethodRevokeCertificate, func(req []byte) (response []byte, err error) {
certs, err := x509.ParseCertificates(req)
if err != nil || len(certs) == 0 {
var revReq struct {
Cert []byte
Reason core.RevocationCode
RegID *int64
}
if err = json.Unmarshal(req, &revReq); err != nil {
// AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64
improperMessage(MethodRevokeCertificate, err, req)
return
}
cert, err := x509.ParseCertificate(revReq.Cert)
if err != nil {
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
return
}
err = impl.RevokeCertificate(*certs[0])
err = impl.RevokeCertificate(*cert, revReq.Reason, revReq.RegID)
return
})
@ -399,8 +408,20 @@ func (rac RegistrationAuthorityClient) UpdateAuthorization(authz core.Authorizat
}
// RevokeCertificate sends a Revoke Certificate request
func (rac RegistrationAuthorityClient) RevokeCertificate(cert x509.Certificate) (err error) {
_, err = rac.rpc.DispatchSync(MethodRevokeCertificate, cert.Raw)
func (rac RegistrationAuthorityClient) RevokeCertificate(cert x509.Certificate, reason core.RevocationCode, regID *int64) (err error) {
var revReq struct {
Cert []byte
Reason core.RevocationCode
RegID *int64
}
revReq.Cert = cert.Raw
revReq.Reason = reason
revReq.RegID = regID
data, err := json.Marshal(revReq)
if err != nil {
return
}
_, err = rac.rpc.DispatchSync(MethodRevokeCertificate, data)
return
}
@ -613,7 +634,7 @@ func (cac CertificateAuthorityClient) IssueCertificate(csr x509.CertificateReque
}
// RevokeCertificate sends a request to revoke a certificate
func (cac CertificateAuthorityClient) RevokeCertificate(serial string, reasonCode int) (err error) {
func (cac CertificateAuthorityClient) RevokeCertificate(serial string, reasonCode core.RevocationCode) (err error) {
var revokeReq revokeCertificateRequest
revokeReq.Serial = serial
revokeReq.ReasonCode = reasonCode
@ -1044,7 +1065,7 @@ func (cac StorageAuthorityClient) GetCertificateStatus(id string) (status core.C
}
// MarkCertificateRevoked sends a request to mark a certificate as revoked
func (cac StorageAuthorityClient) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode int) (err error) {
func (cac StorageAuthorityClient) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode core.RevocationCode) (err error) {
var mcrReq markCertificateRevokedRequest
mcrReq.Serial = serial

View File

@ -344,7 +344,7 @@ func (ssa *SQLStorageAuthority) UpdateOCSP(serial string, ocspResponse []byte) (
// MarkCertificateRevoked stores the fact that a certificate is revoked, along
// with a timestamp and a reason.
func (ssa *SQLStorageAuthority) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode int) (err error) {
func (ssa *SQLStorageAuthority) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode core.RevocationCode) (err error) {
if _, err = ssa.GetCertificate(serial); err != nil {
return fmt.Errorf(
"Unable to mark certificate %s revoked: cert not found.", serial)

View File

@ -892,7 +892,7 @@ func (ra *MockRegistrationAuthority) UpdateAuthorization(authz core.Authorizatio
return authz, nil
}
func (ra *MockRegistrationAuthority) RevokeCertificate(cert x509.Certificate) error {
func (ra *MockRegistrationAuthority) RevokeCertificate(cert x509.Certificate, reason core.RevocationCode, reg *int64) error {
return nil
}

View File

@ -640,7 +640,8 @@ func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, requ
return
}
err = wfe.RA.RevokeCertificate(*parsedCertificate)
// Use revocation code 0, meaning "unspecified"
err = wfe.RA.RevokeCertificate(*parsedCertificate, 0, &registration.ID)
if err != nil {
logEvent.Error = err.Error()
wfe.sendError(response, "Failed to revoke certificate", err, statusCodeFromError(err))

View File

@ -241,7 +241,7 @@ func (sa *MockSA) FinalizeAuthorization(authz core.Authorization) (err error) {
return
}
func (sa *MockSA) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode int) (err error) {
func (sa *MockSA) MarkCertificateRevoked(serial string, ocspResponse []byte, reasonCode core.RevocationCode) (err error) {
return
}
@ -289,7 +289,7 @@ func (ra *MockRegistrationAuthority) UpdateAuthorization(authz core.Authorizatio
return authz, nil
}
func (ra *MockRegistrationAuthority) RevokeCertificate(cert x509.Certificate) error {
func (ra *MockRegistrationAuthority) RevokeCertificate(cert x509.Certificate, reason core.RevocationCode, reg *int64) error {
return nil
}
@ -310,7 +310,7 @@ func (ca *MockCA) GenerateOCSP(xferObj core.OCSPSigningRequest) (ocsp []byte, er
return
}
func (ca *MockCA) RevokeCertificate(serial string, reasonCode int) (err error) {
func (ca *MockCA) RevokeCertificate(serial string, reasonCode core.RevocationCode) (err error) {
return
}