Skip to content

Commit

Permalink
Merge 048f10f into ec88d9d
Browse files Browse the repository at this point in the history
  • Loading branch information
jsha committed May 12, 2015
2 parents ec88d9d + 048f10f commit 1482c0d
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 10 deletions.
1 change: 1 addition & 0 deletions cmd/boulder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func main() {
// Wire them up
wfe.RA = &ra
wfe.SA = sa
wfe.CA = ca
wfe.Stats = stats

wfe.IssuerCert, err = cmd.LoadCert(c.CA.IssuerCert)
Expand Down
7 changes: 7 additions & 0 deletions core/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ func Fingerprint256(data []byte) string {
return B64enc(d.Sum(nil))
}

func KeyDigest(key crypto.PublicKey) string {
keyDER, _ := x509.MarshalPKIXPublicKey(key)
spkiDigest := sha256.Sum256(keyDER)
fmt.Println(base64.StdEncoding.EncodeToString(keyDER))
return base64.StdEncoding.EncodeToString(spkiDigest[0:32])
}

// URLs that automatically marshal/unmarshal to JSON strings
type AcmeURL url.URL

Expand Down
3 changes: 1 addition & 2 deletions ra/registration-authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,7 @@ func (ra *RegistrationAuthorityImpl) UpdateAuthorization(base core.Authorization
}

func (ra *RegistrationAuthorityImpl) RevokeCertificate(cert x509.Certificate) error {
// TODO: ra.CA.RevokeCertificate()
return nil
return ra.CA.RevokeCertificate(core.SerialToString(cert.SerialNumber))
}

func (ra *RegistrationAuthorityImpl) OnValidationUpdate(authz core.Authorization) {
Expand Down
3 changes: 3 additions & 0 deletions sa/storage-authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ func (ssa *SQLStorageAuthority) InitTables() (err error) {
ssa.dbMap.AddTableWithName(core.CertificateStatus{}, "certificateStatus").SetKeys(false, "Serial").SetVersionCol("LockCol")
ssa.dbMap.AddTableWithName(core.OcspResponse{}, "ocspResponses").SetKeys(true, "ID")
ssa.dbMap.AddTableWithName(core.Crl{}, "crls").SetKeys(false, "Serial")
// TODO: Add these indexes for efficient OCSP serving.
// `CREATE INDEX IF NOT EXISTS serial_createdAt on ocspResponses (serial, createdAt)`,
// `CREATE INDEX IF NOT EXISTS serial_createdAt on crls (serial, createdAt)`,

err = ssa.dbMap.CreateTablesIfNotExists()
return
Expand Down
45 changes: 45 additions & 0 deletions test/js/revoke.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2014 ISRG. All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// To revoke a certificate against a local Boulder:
// js revoke.js cert.pem key.pem

'use strict';

var crypto = require('./crypto-util');
var util = require('./acme-util');
var forge = require('node-forge');
var fs = require('fs');
var request = require('request');

function main() {
if (process.argv.length != 4) {
console.log('Usage: js revoke.js cert.der key.pem');
process.exit(1);
}
var key = crypto.importPemPrivateKey(fs.readFileSync(process.argv[3]));
var certDER = fs.readFileSync(process.argv[2])
var certDERB64URL = util.b64enc(new Buffer(certDER))
var revokeMessage = JSON.stringify({
// For some reason forge adds an extra, incorrect '00' at the front of the
// serial number.
certificate: certDERB64URL
});
console.log('Requesting revocation:', revokeMessage)
var jws = crypto.generateSignature(key, new Buffer(revokeMessage));
var req = request.post('http://localhost:4000/acme/revoke-cert/', function(err, resp) {
if (err) {
console.log('Error: ', err);
}
console.log(resp.statusCode);
console.log(resp.headers);
console.log(resp.body);
});
var payload = JSON.stringify(jws);
console.log(payload);
req.write(payload);
req.end();
}
main();
2 changes: 0 additions & 2 deletions test/js/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,6 @@ function sendResponse() {

cli.spinner("Validating domain");

var options = url.parse(state.responseURL);
options.method = "POST";
var req = request.post(state.responseURL, {}, ensureValidation);
req.write(payload)
req.end();
Expand Down
93 changes: 87 additions & 6 deletions wfe/web-front-end.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package wfe

import (
"bytes"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
Expand All @@ -26,6 +28,7 @@ import (
type WebFrontEndImpl struct {
RA core.RegistrationAuthority
SA core.StorageGetter
CA core.CertificateAuthority
Stats statsd.Statter
log *blog.AuditLogger

Expand All @@ -43,6 +46,7 @@ type WebFrontEndImpl struct {
NewCertPath string
CertBase string
CertPath string
RevokeCertPath string
TermsPath string
IssuerPath string

Expand All @@ -62,6 +66,7 @@ func NewWebFrontEndImpl() WebFrontEndImpl {
NewCertPath: "/acme/new-cert",
CertPath: "/acme/cert/",
TermsPath: "/terms",
RevokeCertPath: "/acme/revoke-cert/",
IssuerPath: "/acme/issuer-cert",
}
}
Expand All @@ -81,6 +86,7 @@ func (wfe *WebFrontEndImpl) HandlePaths() {
http.HandleFunc(wfe.RegPath, wfe.Registration)
http.HandleFunc(wfe.AuthzPath, wfe.Authorization)
http.HandleFunc(wfe.CertPath, wfe.Certificate)
http.HandleFunc(wfe.RevokeCertPath, wfe.RevokeCertificate)
http.HandleFunc(wfe.TermsPath, wfe.Terms)
http.HandleFunc(wfe.IssuerPath, wfe.Issuer)
}
Expand Down Expand Up @@ -291,6 +297,87 @@ func (wfe *WebFrontEndImpl) NewAuthorization(response http.ResponseWriter, reque
wfe.Stats.Inc("PendingAuthorizations", 1, 1.0)
}

func (wfe *WebFrontEndImpl) RevokeCertificate(response http.ResponseWriter, request *http.Request) {
if request.Method != "POST" {
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
return
}

body, requestKey, err := verifyPOST(request)
if err != nil {
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
return
}

type RevokeRequest struct {
CertificateDER jose.JsonBuffer `json:"certificate"`
}
var revokeRequest RevokeRequest
if err = json.Unmarshal(body, &revokeRequest); err != nil {
wfe.log.Debug(fmt.Sprintf("Couldn't unmarshal in revoke request %s", string(body)))
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
return
}
providedCert, err := x509.ParseCertificate(revokeRequest.CertificateDER)
if err != nil {
wfe.log.Debug("Couldn't parse cert in revoke request.")
wfe.sendError(response, "Unable to read/verify body", http.StatusBadRequest)
return
}

serial := core.SerialToString(providedCert.SerialNumber)
certDER, err := wfe.SA.GetCertificate(serial)
if err != nil || !bytes.Equal(certDER, revokeRequest.CertificateDER) {
wfe.sendError(response, "No such certificate", http.StatusNotFound)
return
}
parsedCertificate, err := x509.ParseCertificate(certDER)
if err != nil {
wfe.sendError(response, "Invalid certificate", http.StatusInternalServerError)
return
}

certStatus, err := wfe.SA.GetCertificateStatus(serial)
if err != nil {
wfe.sendError(response, "No such certificate", http.StatusNotFound)
return
}

if certStatus.Status == core.OCSPStatusRevoked {
wfe.sendError(response, "Certificate already revoked", http.StatusConflict)
return
}

// TODO: Allow other types of keys.
if requestKey.Rsa == nil {
wfe.sendError(response, "Non-RSA keys not permitted.", http.StatusForbidden)
return
}
// TODO: Implement other methods of validating revocation, e.g. through
// authorizations on account.
if core.KeyDigest(requestKey.Rsa) != core.KeyDigest(parsedCertificate.PublicKey) {
wfe.log.Debug(fmt.Sprintf("Key mismatch for revoke: %s vs %s",
core.KeyDigest(requestKey),
core.KeyDigest(parsedCertificate.PublicKey)))
wfe.sendError(response,
"Revocation request must be signed by private key of cert to be revoked",
http.StatusForbidden)
return
}

err = wfe.RA.RevokeCertificate(*parsedCertificate)
if err != nil {
wfe.sendError(response,
"Failed to revoke certificate",
http.StatusInternalServerError)
} else {
wfe.log.Debug(fmt.Sprintf("Revoked %v", serial))
// incr revoked cert stat
wfe.Stats.Inc("RevokedCertificates", 1, 1.0)
response.WriteHeader(http.StatusOK)
}
}

func (wfe *WebFrontEndImpl) NewCertificate(response http.ResponseWriter, request *http.Request) {
if request.Method != "POST" {
wfe.sendError(response, "Method not allowed", http.StatusMethodNotAllowed)
Expand Down Expand Up @@ -562,12 +649,6 @@ func (wfe *WebFrontEndImpl) Certificate(response http.ResponseWriter, request *h
if _, err = response.Write(cert); err != nil {
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
}

case "POST":
// TODO: Handle revocation in POST

// incr revoked cert stat
wfe.Stats.Inc("RevokedCertificates", 1, 1.0)
}
}

Expand Down

0 comments on commit 1482c0d

Please sign in to comment.