diff options
Diffstat (limited to 'cmd/silentct-mac')
-rw-r--r-- | cmd/silentct-mac/examples.help2man | 6 | ||||
-rw-r--r-- | cmd/silentct-mac/main.go | 121 | ||||
-rw-r--r-- | cmd/silentct-mac/name.help2man | 2 | ||||
-rw-r--r-- | cmd/silentct-mac/see-also.help2man | 2 |
4 files changed, 131 insertions, 0 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/silentct-mac/main.go b/cmd/silentct-mac/main.go new file mode 100644 index 0000000..2add812 --- /dev/null +++ b/cmd/silentct-mac/main.go @@ -0,0 +1,121 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "os" + "strings" + + "rgdd.se/silent-ct/internal/flagopt" + "rgdd.se/silent-ct/internal/ioutil" + "rgdd.se/silent-ct/internal/logger" + "rgdd.se/silent-ct/pkg/crtutil" + "rgdd.se/silent-ct/pkg/policy" + "rgdd.se/silent-ct/pkg/submission" +) + +const usage = ` +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: silentct-mac [Options] -n NAME -s SECRET CRT-FILE [CRT-FILE ...] + +Options: + -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) +` + +type config struct { + // Options + name string + output string + secret string + verbosity string + + // Extracted + log *logger.Logger + files []string +} + +func configure(cmd string, args []string) (cfg config, err error) { + fs := flag.NewFlagSet(cmd, flag.ContinueOnError) + fs.Usage = func() {} + flagopt.StringOpt(fs, &cfg.name, "name", "n", "") + 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 + 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 + cfg.files = fs.Args() + if len(cfg.files) == 0 { + return cfg, fmt.Errorf("at least one certificate chain file is required") + } + + return cfg, err +} + +func main() { + cfg, err := configure(os.Args[0], os.Args[1:]) + if err != nil { + if errors.Is(err, flag.ErrHelp) { + fmt.Fprintf(os.Stdout, "%s", usage[1:]) + os.Exit(0) + } + if !strings.Contains(err.Error(), "flag provided but not defined") { + fmt.Fprintf(os.Stdout, "%v\n", err) + } + os.Exit(1) + } + + var chains [][]byte + for i, path := range cfg.files { + b, err := ioutil.ReadData(path) + if err != nil { + cfg.log.Dief("file %d: %v\n", i, err) + } + if _, err := crtutil.CertificateChainFromPEM(b); err != nil { + cfg.log.Dief("file %d: %v\n", i, err) + } + + chains = append(chains, b) + } + + node, err := policy.NewNode(cfg.name, cfg.secret, "http://www.example.org/unused", nil) + if err != nil { + cfg.log.Dief("api: %v\n", err) + } + s, err := submission.New(node, chains) + if err != nil { + cfg.log.Dief("api: %v\n", err) + } + + fp := os.Stdout + if cfg.output != "" { + if fp, err = os.OpenFile(cfg.output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil { + cfg.log.Dief("output: %v\n", err) + } + } + + fmt.Fprintf(fp, "%s", string(s)) +} 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) |