From aba0f17953c9947bb51e78ed581f4e66b7012518 Mon Sep 17 00:00:00 2001
From: Rasmus Dahlberg <rgdd@glasklarteknik.se>
Date: Thu, 16 May 2024 12:48:22 +0200
Subject: Add man pages and installer Makefile

Includes renaming of the tools, part one of trying to simplify
terminology and letting go of "node" and "moon".  Improving the
terminology was suggested by Martin H a while back, thank you.
---
 cmd/silentct-mac/examples.help2man |   6 ++
 cmd/silentct-mac/main.go           | 121 +++++++++++++++++++++++++++++++++++++
 cmd/silentct-mac/name.help2man     |   2 +
 cmd/silentct-mac/see-also.help2man |   2 +
 4 files changed, 131 insertions(+)
 create mode 100644 cmd/silentct-mac/examples.help2man
 create mode 100644 cmd/silentct-mac/main.go
 create mode 100644 cmd/silentct-mac/name.help2man
 create mode 100644 cmd/silentct-mac/see-also.help2man

(limited to 'cmd/silentct-mac')

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)
-- 
cgit v1.2.3