diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/silentct-mac/examples.help2man | 6 | ||||
-rw-r--r-- | cmd/silentct-mac/main.go (renamed from cmd/silent-ctnode/main.go) | 42 | ||||
-rw-r--r-- | cmd/silentct-mac/name.help2man | 2 | ||||
-rw-r--r-- | cmd/silentct-mac/see-also.help2man | 2 | ||||
-rw-r--r-- | cmd/silentct-mon/examples.help2man | 38 | ||||
-rw-r--r-- | cmd/silentct-mon/main.go (renamed from cmd/silent-ctmoon/main.go) | 60 | ||||
-rw-r--r-- | cmd/silentct-mon/name.help2man | 2 | ||||
-rw-r--r-- | cmd/silentct-mon/see-also.help2man | 2 |
8 files changed, 99 insertions, 55 deletions
diff --git a/cmd/silentct-mac/examples.help2man b/cmd/silentct-mac/examples.help2man new file mode 100644 index 0000000..f7bbff5 --- /dev/null +++ b/cmd/silentct-mac/examples.help2man @@ -0,0 +1,6 @@ +[EXAMPLES] +Allowlist the current certificate in a Let's Encrypt deployment: + +.B $ silentct-mac -n example.org -s sikritpassword -o /var/www/example.org/silent-ct/allowlist /etc/letsencrypt/live/example.org/fullchain.pem + +You may run the above as part of your crontab or certbot renewal configuration. diff --git a/cmd/silent-ctnode/main.go b/cmd/silentct-mac/main.go index 99f4437..2add812 100644 --- a/cmd/silent-ctnode/main.go +++ b/cmd/silentct-mac/main.go @@ -16,32 +16,26 @@ import ( ) const usage = ` -A utility that generates a submission of one or more certificate chains. -The generated submission is protected by a message authentication code. +silentct-mac is a utility that helps allowlist legitimately issued certificates +while monitoring Certificate Transparency logs. One or more certificate chains +are bundled with a message authentication code, such that the silentct-mon tool +can fetch them over an insecure channel or from untrusted intermediary storage. -Usage: - - silent-ctnode --help - silent-ctnode [Options] -n NAME -s SECRET FILE [FILE ...] +Usage: silentct-mac [Options] -n NAME -s SECRET CRT-FILE [CRT-FILE ...] Options: - - -h, --help: Output usage message and exit + -n, --name Name of the system that allowlists certificates + -o, --output Filename to write allowlisted certificates to (default: stdout) + -s, --secret Shared secret between the allowlisting system and its monitor -v, --verbosity Leveled logging output (default: NOTICE) - - -n, --name: Name of the node generating the submission - -s, --secret: Shared secret between the node and its monitor - -o, --output: File to write submission to (default: stdout) - -Each trailing FILE argument must contain a single certificate chain. ` type config struct { // Options - verbosity string name string - secret string output string + secret string + verbosity string // Extracted log *logger.Logger @@ -51,25 +45,25 @@ type config struct { func configure(cmd string, args []string) (cfg config, err error) { fs := flag.NewFlagSet(cmd, flag.ContinueOnError) fs.Usage = func() {} - flagopt.StringOpt(fs, &cfg.verbosity, "verbosity", "v", logger.LevelNotice.String()) flagopt.StringOpt(fs, &cfg.name, "name", "n", "") - flagopt.StringOpt(fs, &cfg.secret, "secret", "s", "") flagopt.StringOpt(fs, &cfg.output, "output", "o", "") + flagopt.StringOpt(fs, &cfg.secret, "secret", "s", "") + flagopt.StringOpt(fs, &cfg.verbosity, "verbosity", "v", logger.LevelNotice.String()) if err = fs.Parse(args); err != nil { return cfg, err } // Options - lv, err := logger.NewLevel(cfg.verbosity) - if err != nil { - return cfg, fmt.Errorf("invalid verbosity: %v", err) - } if cfg.name == "" { return cfg, fmt.Errorf("node name is required") } if cfg.secret == "" { return cfg, fmt.Errorf("node secret is required") } + lv, err := logger.NewLevel(cfg.verbosity) + if err != nil { + return cfg, fmt.Errorf("invalid verbosity: %v", err) + } cfg.log = logger.New(logger.Config{Level: lv, File: os.Stderr}) // Arguments @@ -85,11 +79,11 @@ func main() { cfg, err := configure(os.Args[0], os.Args[1:]) if err != nil { if errors.Is(err, flag.ErrHelp) { - fmt.Fprintf(os.Stderr, "%s", usage[1:]) + fmt.Fprintf(os.Stdout, "%s", usage[1:]) os.Exit(0) } if !strings.Contains(err.Error(), "flag provided but not defined") { - fmt.Fprintf(os.Stderr, "%v\n", err) + fmt.Fprintf(os.Stdout, "%v\n", err) } os.Exit(1) } diff --git a/cmd/silentct-mac/name.help2man b/cmd/silentct-mac/name.help2man new file mode 100644 index 0000000..d7f6a28 --- /dev/null +++ b/cmd/silentct-mac/name.help2man @@ -0,0 +1,2 @@ +[NAME] +silentct-mac - allowlist certificates with message authentication codes diff --git a/cmd/silentct-mac/see-also.help2man b/cmd/silentct-mac/see-also.help2man new file mode 100644 index 0000000..02987dc --- /dev/null +++ b/cmd/silentct-mac/see-also.help2man @@ -0,0 +1,2 @@ +[SEE ALSO] +.BR silentct-mon (1) diff --git a/cmd/silentct-mon/examples.help2man b/cmd/silentct-mon/examples.help2man new file mode 100644 index 0000000..7a1e8fc --- /dev/null +++ b/cmd/silentct-mon/examples.help2man @@ -0,0 +1,38 @@ +[EXAMPLES] + +A basic configuration is shown below. + + { + "monitor": [ + { + "bootstrap_at": "2024-05-16T00:00:00Z", + "wildcard": "example.org", + "excludes": [ + "test" + ] + } + ], + "nodes": [ + { + "name": "example.org", + "secret": "sikritpassword", + "url": "https://www.example.org/silent-ct/allowlist", + "issues": [ + "example.org", + "www.example.org" + ] + } + ] + } + +Bootstrap a new monitor in a non-existent directory: + +.B $ silentct-mon -b -d ~/.local/lib/silent-ct -f ~/.config/silent-ct/config.json + +Run the monitor continuously: + +.B $ silentct-mon -d ~/.local/lib/silent-ct -f ~/.config/silent-ct/config.json + +Use +.B -v DEBUG +to see what's happening underneath the hood. diff --git a/cmd/silent-ctmoon/main.go b/cmd/silentct-mon/main.go index c651e68..2d070fb 100644 --- a/cmd/silent-ctmoon/main.go +++ b/cmd/silentct-mon/main.go @@ -23,28 +23,27 @@ import ( ) const usage = ` -A utility that follows relevant Certificate Transparency logs to -discover certificates that may be mis-issued. To be silent, any -legitimately issued certificates are pulled from trusted nodes. +silentct-mon is a tool that monitors Certificate Transparency logs. The tool +can operate silently, which means there need not be any output unless a +certificate is possibly mis-issued. This requires use of the silentct-mac +utility on the trusted systems that legitimately request certificates. -Usage: +The same list of Certificate Transparency logs as Google Chrome is used. This +list can be overridden in the silentct-mon configuration file. - silent-ctmoon --help - silent-ctmoon [Opts] -d DIRECTORY -f POLICY_FILE +Usage: silentct-mon [Options] -d DIRECTORY -f POLICY-FILE Options: - -h, --help: Output usage message and exit - -v, --verbosity: Leveled logging output (default: NOTICE) - - -b, --bootstrap: Initializate a new state directory (Default: false) - -c, --contact: A string that helps log operators know who you are (Default: "") - -d, --directory: Path to a directory where all state will be stored - -e, --please-exit Toggle to only run until up-to-date (Default: false) - -f, --policy-file: Path to the monitor's policy file in JSON format + -b, --bootstrap Initializes a new state directory (Default: false) + -c, --contact A string that helps log operators know who you are (Default: "") + -d, --directory Path to a directory where all state will be stored + -w, --num-workers Number of parallel workers to fetch each log with (Default: 1) -o, --output-file File that all output will be written to (Default: stdout) - -p, --pull-interval: How often nodes are pulled for certificates (Default: 15m) - -w, --num-workers: Number of parallel workers to fetch each log with (Default: 1) + -e, --please-exit Toggle to only run until up-to-date (Default: false) + -f, --policy-file Path to the monitor's policy file in JSON format + -p, --pull-interval How often nodes are pulled for certificates (Default: 15m) + -v, --verbosity Leveled logging output (default: NOTICE) ` type config struct { @@ -67,29 +66,25 @@ type config struct { func configure(cmd string, args []string) (cfg config, err error) { fs := flag.NewFlagSet(cmd, flag.ContinueOnError) fs.Usage = func() {} - flagopt.StringOpt(fs, &cfg.verbosity, "verbosity", "v", logger.LevelNotice.String()) flagopt.BoolOpt(fs, &cfg.bootstrap, "bootstrap", "b", false) flagopt.StringOpt(fs, &cfg.contact, "contact", "c", "") flagopt.StringOpt(fs, &cfg.directory, "directory", "d", "") + flagopt.UintOpt(fs, &cfg.numWorkers, "num-workers", "w", 1) + flagopt.StringOpt(fs, &cfg.outputFile, "output-file", "o", "") flagopt.BoolOpt(fs, &cfg.pleaseExit, "please-exit", "e", false) flagopt.StringOpt(fs, &cfg.policyFile, "policy-file", "f", "") - flagopt.StringOpt(fs, &cfg.outputFile, "output-file", "o", "") flagopt.DurationOpt(fs, &cfg.pullInterval, "pull-interval", "p", 15*time.Minute) - flagopt.UintOpt(fs, &cfg.numWorkers, "num-workers", "w", 1) + flagopt.StringOpt(fs, &cfg.verbosity, "verbosity", "v", logger.LevelNotice.String()) if err = fs.Parse(args); err != nil { return cfg, err } // Options - lv, err := logger.NewLevel(cfg.verbosity) - if err != nil { - return cfg, fmt.Errorf("invalid verbosity: %v", err) - } if cfg.directory == "" { return cfg, fmt.Errorf("directory is a required option") } - if cfg.policyFile == "" { - return cfg, fmt.Errorf("policy file is a required option") + if cfg.numWorkers == 0 || cfg.numWorkers >= 4 { + return cfg, fmt.Errorf("number of workers must be in [1, 4)") } output := os.Stdout if cfg.outputFile != "" { @@ -97,17 +92,20 @@ func configure(cmd string, args []string) (cfg config, err error) { return cfg, fmt.Errorf("failed to open output file: %v", err) } } - if cfg.numWorkers == 0 || cfg.numWorkers > 4 { - return cfg, fmt.Errorf("number of workers must be in [1, 4]") + if cfg.policyFile == "" { + return cfg, fmt.Errorf("policy file is a required option") } - - cfg.log = logger.New(logger.Config{Level: lv, File: output}) if err := ioutil.ReadJSON(cfg.policyFile, &cfg.policy); err != nil { return cfg, err } if len(cfg.policy.Monitor) == 0 { return cfg, fmt.Errorf("policy: need at least one wildcard to monitor") } + lv, err := logger.NewLevel(cfg.verbosity) + if err != nil { + return cfg, fmt.Errorf("invalid verbosity: %v", err) + } + cfg.log = logger.New(logger.Config{Level: lv, File: output}) // Arguments if len(fs.Args()) != 0 { @@ -121,11 +119,11 @@ func main() { cfg, err := configure(os.Args[0], os.Args[1:]) if err != nil { if errors.Is(err, flag.ErrHelp) { - fmt.Fprintf(os.Stderr, "%s", usage[1:]) + fmt.Fprintf(os.Stdout, "%s", usage[1:]) os.Exit(0) } if !strings.Contains(err.Error(), "flag provided but not defined") { - fmt.Fprintf(os.Stderr, "%v\n", err) + fmt.Fprintf(os.Stdout, "%v\n", err) } os.Exit(1) } diff --git a/cmd/silentct-mon/name.help2man b/cmd/silentct-mon/name.help2man new file mode 100644 index 0000000..a4edcc1 --- /dev/null +++ b/cmd/silentct-mon/name.help2man @@ -0,0 +1,2 @@ +[NAME] +silentct-mon - monitor Certificate Transparency logs diff --git a/cmd/silentct-mon/see-also.help2man b/cmd/silentct-mon/see-also.help2man new file mode 100644 index 0000000..d4b9782 --- /dev/null +++ b/cmd/silentct-mon/see-also.help2man @@ -0,0 +1,2 @@ +[SEE ALSO] +.BR silentct-mac (1) |