Purge POST'd OCSP responses as well as GETs (#2449)

Akamai expects a special URL to be used to purge responses from POST'd requests, this change adds those URLs to the existing GET URLs when purging OCSP responses.

Note this assumes all POST requests encode their OCSP request in the same manner that Golang does, which is most likely not the case in some situations. In order to mimic all the possible formats we would need to write a bunch of custom ASN.1 definitions that conform with specific field use/order that browsers etc use and generate a URL for each of those as well.

Fixes #996.
This commit is contained in:
Roland Bracewell Shoemaker 2017-01-18 09:30:15 -08:00 committed by Jacob Hoffman-Andrews
parent 714ec98a0c
commit cb64fee358
2 changed files with 33 additions and 3 deletions

View File

@ -1,6 +1,7 @@
package main
import (
"crypto/md5"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
@ -199,6 +200,21 @@ func newUpdater(
return &updater, nil
}
func reverseBytes(b []byte) []byte {
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
return b
}
func generatePOSTURL(der []byte, ocspServer string) string {
// Generate POST url, format is the URL that was POST'd to with a query string with
// the parameter 'body-mdy' and the value of the first two uint32s in little endian
// order in hex of the MD5 hash of the OCSP request body.
hash := md5.Sum(der)
return fmt.Sprintf("%s?body-mdy=%x%x", ocspServer, reverseBytes(hash[0:4]), reverseBytes(hash[4:8]))
}
// sendPurge should only be called as a Goroutine as it will block until the purge
// request is successful
func (updater *OCSPUpdater) sendPurge(der []byte) {
@ -214,18 +230,18 @@ func (updater *OCSPUpdater) sendPurge(der []byte) {
return
}
// Create a GET style OCSP url for each endpoint in cert.OCSPServer (still waiting
// on word from Akamai on how to properly purge cached POST requests, for now just
// do GET)
// Create a GET and special Akamai POST style OCSP url for each endpoint in cert.OCSPServer
urls := []string{}
for _, ocspServer := range cert.OCSPServer {
if !strings.HasSuffix(ocspServer, "/") {
ocspServer += "/"
}
// Generate GET url
urls = append(
urls,
fmt.Sprintf("%s%s", ocspServer, url.QueryEscape(base64.StdEncoding.EncodeToString(req))),
)
urls = append(urls, generatePOSTURL(der, ocspServer))
}
err = updater.ccu.Purge(urls)

View File

@ -851,3 +851,17 @@ func TestMissingLogs(t *testing.T) {
}
}
}
func TestReverseBytes(t *testing.T) {
a := []byte{0, 1, 2, 3}
test.AssertDeepEquals(t, reverseBytes(a), []byte{3, 2, 1, 0})
}
func TestGeneratePOSTURL(t *testing.T) {
der := []byte{0}
test.AssertEquals(
t,
generatePOSTURL(der, "ocsp.invalid/"),
"ocsp.invalid/?body-mdy=ad85b89389a00dfe",
)
}