go/cmd/aggregate-crls/crl-auditor.go (188 lines of code) (raw):
package main
import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/url"
"sync"
"time"
"github.com/golang/glog"
"github.com/mozilla/crlite/go"
"github.com/mozilla/crlite/go/downloader"
"github.com/mozilla/crlite/go/rootprogram"
)
var (
AuditKindFailedDownload CrlAuditEntryKind = "Failed Download"
AuditKindFailedProcessLocal CrlAuditEntryKind = "Failed Process Local"
AuditKindFailedVerify CrlAuditEntryKind = "Failed Verify"
AuditKindOlderThanLast CrlAuditEntryKind = "Older Than Previous"
AuditKindNoRevocations CrlAuditEntryKind = "Empty Revocation List"
AuditKindOld CrlAuditEntryKind = "Not Fresh, Warning"
AuditKindExpired CrlAuditEntryKind = "Expired, Allowed"
AuditKindValid CrlAuditEntryKind = "Valid, Processed"
)
type CrlAuditEntryKind string
type CrlAuditEntry struct {
Timestamp time.Time
Url string `json:",omitempty"`
Path string `json:",omitempty"`
Age string `json:",omitempty"`
Issuer downloader.DownloadIdentifier
IssuerSubject string
Kind CrlAuditEntryKind
Errors []string `json:",omitempty"`
DNSResults []string `json:",omitempty"`
NumRevocations int `json:",omitempty"`
SHA256Sum string `json:",omitempty"`
}
type CrlAuditor struct {
mutex *sync.Mutex
issuers *rootprogram.MozIssuers
Entries []CrlAuditEntry
}
func NewCrlAuditor(issuers *rootprogram.MozIssuers) *CrlAuditor {
return &CrlAuditor{
mutex: &sync.Mutex{},
issuers: issuers,
Entries: []CrlAuditEntry{},
}
}
func (auditor *CrlAuditor) getSubject(identifier downloader.DownloadIdentifier) string {
issuer, ok := identifier.(*types.Issuer)
if !ok {
return ""
}
subject, err := auditor.issuers.GetSubjectForIssuer(*issuer)
if err != nil {
glog.Warningf("Could not get subject for issuer %s: %v", issuer.ID(), err)
return ""
}
return subject
}
func (auditor *CrlAuditor) GetEntries() []CrlAuditEntry {
return auditor.Entries
}
func (auditor *CrlAuditor) WriteReport(fd io.Writer) error {
enc := json.NewEncoder(fd)
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
return enc.Encode(auditor)
}
func (auditor *CrlAuditor) FailedDownload(issuer downloader.DownloadIdentifier, crlUrl *url.URL, dlTracer *downloader.DownloadTracer, err error) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindFailedDownload,
Url: crlUrl.String(),
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Errors: append(dlTracer.Errors(), err.Error()),
DNSResults: dlTracer.DNSResults(),
})
}
func (auditor *CrlAuditor) FailedVerifyUrl(issuer downloader.DownloadIdentifier, crlUrl *url.URL, dlTracer *downloader.DownloadTracer, err error) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindFailedVerify,
Url: crlUrl.String(),
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Errors: append(dlTracer.Errors(), err.Error()),
DNSResults: dlTracer.DNSResults(),
})
}
func (auditor *CrlAuditor) FailedOlderThanPrevious(issuer downloader.DownloadIdentifier, crlUrl *url.URL, dlTracer *downloader.DownloadTracer, previous time.Time, this time.Time) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
err := fmt.Sprintf("Previous: %s, This Run: %s", previous, this)
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindOlderThanLast,
Url: crlUrl.String(),
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Errors: append(dlTracer.Errors(), err),
DNSResults: dlTracer.DNSResults(),
})
}
func (auditor *CrlAuditor) Old(issuer downloader.DownloadIdentifier, crlUrl *url.URL, age time.Duration) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindOld,
Url: crlUrl.String(),
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Age: age.String(),
})
}
func (auditor *CrlAuditor) Expired(issuer downloader.DownloadIdentifier, crlUrl *url.URL, nextUpdate time.Time) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindExpired,
Url: crlUrl.String(),
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Errors: []string{fmt.Sprintf("Expired, NextUpdate was %s", nextUpdate)},
})
}
func (auditor *CrlAuditor) FailedVerifyPath(issuer downloader.DownloadIdentifier, crlUrl *url.URL, crlPath string, err error) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindFailedVerify,
Url: crlUrl.String(),
Path: crlPath,
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Errors: []string{err.Error()},
})
}
func (auditor *CrlAuditor) FailedProcessLocal(issuer downloader.DownloadIdentifier, crlUrl *url.URL, crlPath string, err error) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindFailedProcessLocal,
Url: crlUrl.String(),
Path: crlPath,
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Errors: []string{err.Error()},
})
}
func (auditor *CrlAuditor) NoRevocations(issuer downloader.DownloadIdentifier, crlUrl *url.URL, crlPath string) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindNoRevocations,
Url: crlUrl.String(),
Path: crlPath,
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
})
}
func (auditor *CrlAuditor) ValidAndProcessed(issuer downloader.DownloadIdentifier, crlUrl *url.URL, crlPath string, numRevocations int, age time.Duration, sha256 []byte) {
auditor.mutex.Lock()
defer auditor.mutex.Unlock()
auditor.Entries = append(auditor.Entries, CrlAuditEntry{
Timestamp: time.Now().UTC(),
Kind: AuditKindValid,
Url: crlUrl.String(),
Path: crlPath,
Issuer: issuer,
IssuerSubject: auditor.getSubject(issuer),
Age: age.String(),
SHA256Sum: hex.EncodeToString(sha256),
NumRevocations: numRevocations,
})
}