Skip to content

Commit

Permalink
tlsobs-runner: an api client to scan targets regularly and notify on …
Browse files Browse the repository at this point in the history
…assertions failures
  • Loading branch information
jvehent committed Dec 29, 2015
1 parent 3e0ac2f commit 1e28275
Show file tree
Hide file tree
Showing 6 changed files with 578 additions and 0 deletions.
102 changes: 102 additions & 0 deletions conf/runner.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
runs:
- targets:
- accounts.firefox.com
- addon.mozilla.org
- addons.mozilla.org
- api.accounts.firefox.com
- blocklist.addons.mozilla.org
- browserid.org
- builder.addons.mozilla.org
- controller-review.apk.firefox.com
- controller.apk.firefox.com
- diresworb.org
- find.firefox.com
- firefoxos.persona.org
- firefoxusercontent.com
- forum.addons.mozilla.org
- forums.addons.mozilla.org
- gmail.login.persona.org
- hello.firefox.com
- loads.services.mozilla.com
- location.services.mozilla.com
- login.anosrep.org
- login.mozilla.org
- login.persona.org
- marketplace-static.addons.mozilla.net
- marketplace.firefox.com
- mozillausercontent.com
- oauth.accounts.firefox.com
- persona.org
- profile.accounts.firefox.com
- push.hello.firefox.com
- push.services.mozilla.com
- push1.push.hello.firefox.com
- pyrepo.addons.mozilla.org
- readinglist.services.mozilla.com
- receiptcheck.marketplace.firefox.com
- scrypt.accounts.firefox.com
- search.services.mozilla.com
- services.addons.mozilla.org
- shavar.services.mozilla.com
- static.addons.mozilla.net
- static.login.persona.org
- static.marketplace.firefox.com
- tracking.services.mozilla.com
- updates.push.services.mozilla.com
- verifier.accounts.firefox.com
- verifier.login.persona.org
- versioncheck-bg.addons.mozilla.org
- versioncheck.addons.mozilla.org
- www.browserid.org
- www.persona.org
- yahoo.login.persona.org
assertions:
- certificate:
validity:
notAfter: ">30d"
- analysis:
analyzer: mozillaEvaluationWorker
result: '{"level": "intermediate"}'
# daily at midnight
cron: "0 0 * * *"
notifications:
email:
recipients:
- cloudsec@mozilla.com

- targets:
- download.mozilla.org
- download-installer.cdn.mozilla.net
assertions:
- analysis:
analyzer: mozillaEvaluationWorker
result: '{"level": "old"}'
# daily at midnight
cron: "0 0 * * *"
notifications:
email:
recipients:
- cloudsec@mozilla.com

#- targets:
# - mana.mozilla.org
# - public.etherpad-mozilla.org
# - irccloud.mozilla.com
# - discourse.mozilla-community.org
# - api.mig.mozilla.org
# assertions:
# - certificate:
# validity:
# notAfter: ">30d"
# - analysis:
# analyzer: mozillaEvaluationWorker
# result: '{"level": "intermediate"}'
# cron: "* * * * *"
# notifications:
# email:
# recipients:
# - infosec@mozilla.com

smtp:
relay: "gator1:25"
from: "cloudsec@mozilla.com"
129 changes: 129 additions & 0 deletions tlsobs-runner/assertions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* 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/.
*/

package main

import (
"fmt"
"log"
"strconv"
"time"

"github.com/mozilla/tls-observatory/certificate"
"github.com/mozilla/tls-observatory/database"
"github.com/mozilla/tls-observatory/worker"
_ "github.com/mozilla/tls-observatory/worker/mozillaEvaluationWorker"
)

func (r Run) AssertNotBefore(a Assertion, target string, cnb time.Time, notifchan chan Notification) {
if a.Certificate.Validity.NotBefore == "" {
return
}
nbmintime, nbmaxtime, err := parseValidity(a.Certificate.Validity.NotBefore)
if err != nil {
log.Printf("[error] failed to parse validity string %q: %v",
a.Certificate.Validity.NotBefore, err)
return
}
if cnb.Before(nbmintime) || cnb.After(nbmaxtime) {
notifchan <- Notification{
Target: target,
Body: []byte(fmt.Sprintf(`Assertion certificate.validity.notBefore=%q failed because certificate starts on %q`,
a.Certificate.Validity.NotBefore, cnb.String())),
Conf: r.Notifications,
}
} else {
debugprint("Assertion certificate.validity.notBefore=%q passed because certificate starts on %q",
a.Certificate.Validity.NotBefore, cnb.String())
}
return
}

func (r Run) AssertNotAfter(a Assertion, target string, cna time.Time, notifchan chan Notification) {
if a.Certificate.Validity.NotAfter == "" {
return
}
nbmintime, nbmaxtime, err := parseValidity(a.Certificate.Validity.NotAfter)
if err != nil {
log.Printf("[error] failed to parse validity string %q: %v",
a.Certificate.Validity.NotAfter, err)
return
}
if cna.Before(nbmintime) || cna.After(nbmaxtime) {
notifchan <- Notification{
Target: target,
Body: []byte(fmt.Sprintf(`Assertion certificate.validity.notAfter=%q failed because certificate expires on %q`,
a.Certificate.Validity.NotAfter, cna.String())),
Conf: r.Notifications,
}
} else {
debugprint("Assertion certificate.validity.notAfter=%q passed because certificate expires on %q",
a.Certificate.Validity.NotAfter, cna.String())
}

return
}

func parseValidity(validity string) (mintime, maxtime time.Time, err error) {
var (
isDays bool = false
n uint64 = 0
)
suffix := validity[len(validity)-1]
if suffix == 'd' {
isDays = true
suffix = 'h'
}
n, err = strconv.ParseUint(validity[1:len(validity)-1], 10, 64)
if err != nil {
return
}
if isDays {
n = n * 24
}
duration := fmt.Sprintf("%d%c", n, suffix)
d, err := time.ParseDuration(duration)
switch validity[0] {
case '>':
mintime = time.Now().Add(d)
maxtime = time.Date(9998, time.January, 11, 11, 11, 11, 11, time.UTC)
case '<':
// modification date is older than date
mintime = time.Date(1111, time.January, 11, 11, 11, 11, 11, time.UTC)
maxtime = time.Now().Add(d)
}
debugprint("Parsed validity time with mintime '%s' and maxtime '%s'\n",
mintime.String(), maxtime.String())
return
}

func (r Run) AssertAnalysis(a Assertion, results database.Scan, cert certificate.Certificate, notifchan chan Notification) {
analyzer := a.Analysis.Analyzer
if analyzer == "" {
return
}
for _, ran := range results.AnalysisResults {
if ran.Analyzer != analyzer {
continue
}
if _, ok := worker.AvailableWorkers[analyzer]; !ok {
log.Printf("[error] analyzer %q not found\n", analyzer)
return
}
runner := worker.AvailableWorkers[analyzer].Runner
pass, body, err := runner.(worker.HasAssert).Assert(ran.Result, []byte(a.Analysis.Result))
if err != nil {
log.Printf("[error] analyzer %q failed with error %v", analyzer, err)
return
}
if !pass {
notifchan <- Notification{
Target: results.Target,
Body: body,
Conf: r.Notifications,
}
}
}
}
Loading

0 comments on commit 1e28275

Please sign in to comment.