Skip to content
This repository was archived by the owner on Dec 1, 2025. It is now read-only.
Closed
1 change: 1 addition & 0 deletions tlsobs-scanner/workerconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ import (
_ "github.com/mozilla/tls-observatory/worker/sslLabsClientSupport"
_ "github.com/mozilla/tls-observatory/worker/symantecDistrust"
_ "github.com/mozilla/tls-observatory/worker/top1m"
_ "github.com/mozilla/tls-observatory/worker/ocspStatusWorker"
)
81 changes: 81 additions & 0 deletions worker/ocspStatusWorker/ocspStatusWorker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package ocspStatusWorker
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: remove "Worker" from the name, it's already under /worker/


import (
"encoding/json"
"io/ioutil"
"net/http"
"crypto/x509"

"github.com/mozilla/tls-observatory/logger"
"github.com/mozilla/tls-observatory/worker"
"golang.org/x/crypto/ocsp"
"bytes"
"crypto"
"time"
"encoding/base64"
)

var workerName = "ocspStatusWorker"
var workerDesc = `Determines a certificate's status via OCSP'`

var log = logger.GetLogger()

func init() {
worker.RegisterWorker(workerName, worker.Info{Runner: new(ocspStatusWorker), Description: workerDesc})
}

type ocspStatusWorker struct {
status OCSPStatus
}

type OCSPStatus struct {
Status int `json:"status"`
RevokedAt time.Time `json:"revoked_at"`

}

type params struct {
}

func (w ocspStatusWorker) Run(in worker.Input, resChan chan worker.Result) {
res := worker.Result{WorkerName: workerName, Success:false}

rawCert, _ := base64.StdEncoding.DecodeString(in.CertificateChain.Certs[0])
certificate, _ := x509.ParseCertificate(rawCert)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the end entity is already parsed in in.Certificate

rawIssuerCert, _ := base64.StdEncoding.DecodeString(in.CertificateChain.Certs[1])
issuerCertificate, _ := x509.ParseCertificate(rawIssuerCert)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should check for errors here.

It might also be worthwhile to make sure the issuer is the right one (that it sign the end-entity) because ordering isn't always guaranteed. You can use CheckSignatureFrom from the x509 package for this.


opts := &ocsp.RequestOptions{Hash: crypto.SHA256}
req, err := ocsp.CreateRequest(certificate, issuerCertificate, opts)
if err != nil {
res.Errors = append(res.Errors, err.Error())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errors need to be inserted into the response channel, otherwise they will be dropped. Something like this:

func (w runner) error(res chan worker.Result, messageFormat string, args ...interface{}) {
        out, _ := json.Marshal(fmt.Sprintf(messageFormat, args...))
        res <- worker.Result{
                Success:    false,
                WorkerName: workerName,
                Result:     out,
        }
}

and use it as follows:

        if err != nil {
                w.error(res, "there was an error: %v", err)
                return
        }

return
}

httpResponse, err := http.Post(certificate.OCSPServer[0], "application/ocsp-request", bytes.NewReader(req))
if err != nil {
res.Errors = append(res.Errors, err.Error())
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a defer httpResponse.Body.Close()

output, err := ioutil.ReadAll(httpResponse.Body)
if err != nil {
res.Errors = append(res.Errors, err.Error())
return
}

OCSPResponse, err := ocsp.ParseResponse(output, issuerCertificate)
if err != nil {
res.Errors = append(res.Errors, err.Error())
return
}

status := OCSPStatus{ Status:OCSPResponse.Status, RevokedAt:OCSPResponse.RevokedAt }

out, _ := json.Marshal(status)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't ignore errors, you never know what the OCSP response will contain


res.Success = true
res.Result = out

resChan <- res
}