Initial commit
This commit is contained in:
parent
b97f30faf4
commit
c1020c8be7
16 changed files with 118 additions and 209 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,2 +1,2 @@
|
|||
checker-openpgpkey
|
||||
checker-openpgpkey.so
|
||||
checker-email-keys
|
||||
checker-email-keys.so
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ WORKDIR /src
|
|||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=0 go build -ldflags "-X main.Version=${CHECKER_VERSION}" -o /checker-openpgpkey .
|
||||
RUN CGO_ENABLED=0 go build -ldflags "-X main.Version=${CHECKER_VERSION}" -o /checker-email-keys .
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /checker-openpgpkey /checker-openpgpkey
|
||||
COPY --from=builder /checker-email-keys /checker-email-keys
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/checker-openpgpkey"]
|
||||
ENTRYPOINT ["/checker-email-keys"]
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -1,4 +1,4 @@
|
|||
CHECKER_NAME := checker-openpgpkey
|
||||
CHECKER_NAME := checker-email-keys
|
||||
CHECKER_IMAGE := happydomain/$(CHECKER_NAME)
|
||||
CHECKER_VERSION ?= custom-build
|
||||
|
||||
|
|
|
|||
2
NOTICE
2
NOTICE
|
|
@ -1,4 +1,4 @@
|
|||
checker-openpgpkey
|
||||
checker-email-keys
|
||||
Copyright (c) 2026 The happyDomain Authors
|
||||
|
||||
This product is licensed under the MIT License (see LICENSE).
|
||||
|
|
|
|||
43
README.md
43
README.md
|
|
@ -1,4 +1,4 @@
|
|||
# checker-openpgpkey
|
||||
# checker-email-keys
|
||||
|
||||
DANE-Email posture checker for happyDomain.
|
||||
|
||||
|
|
@ -66,28 +66,6 @@ rule engine can fold them into a single `CheckState`.
|
|||
| `smimea_self_signed` | info | Self-signed certificate paired with PKIX-EE usage. |
|
||||
| `smimea_hash_only` | info | Matching-type 1/2 only carries a digest; certificate can't be inspected. |
|
||||
|
||||
## Why a bespoke checker instead of a third-party testsuite?
|
||||
|
||||
There is no canonical "OPENPGPKEY / SMIMEA testsuite" in Go or as a
|
||||
self-hostable online service:
|
||||
|
||||
- `ldns-dane` (NLnet Labs) validates DANE-TLSA and handles SMIMEA only
|
||||
shallowly (it parses the record without deep certificate checks).
|
||||
- `hokey` (Paul Wouters) queries OPENPGPKEY but does not validate the
|
||||
key material.
|
||||
- Online DANE validators (e.g. `dane.sys4.de`, `has-tls-rpt.com`) focus
|
||||
on SMTP DANE-TLSA, not email-identity records.
|
||||
|
||||
The heavy lifting here is standard Go parsing:
|
||||
|
||||
- `github.com/ProtonMail/go-crypto/openpgp` (maintained fork of the
|
||||
deprecated `golang.org/x/crypto/openpgp`) for OpenPGP packet parsing,
|
||||
UIDs, subkeys, revocations, key-lifetime self-signatures.
|
||||
- `crypto/x509` for SMIMEA certificate parsing, validity window, EKU,
|
||||
key-usage, signature-algorithm and key-size checks.
|
||||
- `github.com/miekg/dns` for the DNS+EDNS0+DO query and the `AD` flag
|
||||
read-back used as the DNSSEC-validation signal.
|
||||
|
||||
## Options
|
||||
|
||||
| Id | Type | Default | Description |
|
||||
|
|
@ -107,22 +85,5 @@ Auto-filled by the host: `domain_name`, `subdomain`, `service`,
|
|||
make plugin
|
||||
|
||||
# Standalone HTTP server
|
||||
make && ./checker-openpgpkey -listen :8080
|
||||
make && ./checker-email-keys -listen :8080
|
||||
```
|
||||
|
||||
## HTML report
|
||||
|
||||
The report renders as a self-contained HTML document intended for
|
||||
embedding in an `<iframe>` (the same contract as the other happyDomain
|
||||
checkers). It is organised as:
|
||||
|
||||
1. **Header**: status badge, queried owner name, resolver used, DNSSEC
|
||||
flag.
|
||||
2. **Most common issues (fix these first)**: remediation cards shown
|
||||
*only* when a matching finding was emitted. Each card carries the
|
||||
concrete shell commands / zone-file snippets the user needs.
|
||||
3. **OpenPGP key / SMIMEA record**: structured details for the
|
||||
parsed material (fingerprint, UIDs, subkeys, cert subject/issuer,
|
||||
EKU/KU flags, …).
|
||||
4. **Findings**: the full table of per-finding code / severity /
|
||||
message / fix hints, sorted by severity.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
|
|
@ -123,13 +117,9 @@ func (p *emailKeyProvider) Collect(ctx context.Context, opts sdk.CheckerOptions)
|
|||
data.RecordCount = len(ans.Records)
|
||||
|
||||
if ans.Rcode == dns.RcodeNameError || len(ans.Records) == 0 {
|
||||
sev := SeverityCrit
|
||||
if ans.Rcode == dns.RcodeNameError {
|
||||
sev = SeverityCrit
|
||||
}
|
||||
data.Findings = append(data.Findings, Finding{
|
||||
Code: CodeDNSNoRecord,
|
||||
Severity: sev,
|
||||
Severity: SeverityCrit,
|
||||
Message: fmt.Sprintf("Authoritative DNS returned no %s record at %s.", dns.TypeToString[qtype], data.QueriedOwner),
|
||||
Fix: "Ensure the record is present in the zone and that the zone has been loaded by the authoritative servers.",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
package checker
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,9 +1,3 @@
|
|||
// This file is part of the happyDomain (R) project.
|
||||
// Copyright (c) 2026 happyDomain
|
||||
// Authors: Pierre-Olivier Mercier, et al.
|
||||
//
|
||||
// Licensed under the MIT License (see LICENSE).
|
||||
|
||||
// Package checker implements the OPENPGPKEY/SMIMEA DANE checker for
|
||||
// happyDomain. It runs a comprehensive testsuite on the DNS-published
|
||||
// OpenPGP key (RFC 7929) or S/MIME certificate (RFC 8162) corresponding
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -1,4 +1,4 @@
|
|||
module git.happydns.org/checker-openpgpkey
|
||||
module git.happydns.org/checker-email-keys
|
||||
|
||||
go 1.25.0
|
||||
|
||||
|
|
|
|||
10
main.go
10
main.go
|
|
@ -4,23 +4,23 @@ import (
|
|||
"flag"
|
||||
"log"
|
||||
|
||||
openpgpkey "git.happydns.org/checker-openpgpkey/checker"
|
||||
emailkeys "git.happydns.org/checker-email-keys/checker"
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
var listenAddr = flag.String("listen", ":8080", "HTTP listen address")
|
||||
|
||||
// Version is the standalone binary's version. Override with:
|
||||
//
|
||||
// go build -ldflags "-X main.Version=1.2.3" .
|
||||
var Version = "custom-build"
|
||||
|
||||
var listenAddr = flag.String("listen", ":8080", "HTTP listen address")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
openpgpkey.Version = Version
|
||||
emailkeys.Version = Version
|
||||
|
||||
server := sdk.NewServer(openpgpkey.Provider())
|
||||
server := sdk.NewServer(emailkeys.Provider())
|
||||
if err := server.ListenAndServe(*listenAddr); err != nil {
|
||||
log.Fatalf("server error: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,18 +4,18 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
openpgpkey "git.happydns.org/checker-openpgpkey/checker"
|
||||
emailkeys "git.happydns.org/checker-email-keys/checker"
|
||||
sdk "git.happydns.org/checker-sdk-go/checker"
|
||||
)
|
||||
|
||||
// Version is the plugin's version, meant to be overridden by CI:
|
||||
//
|
||||
// go build -buildmode=plugin -ldflags "-X main.Version=1.2.3" -o checker-openpgpkey.so ./plugin
|
||||
// go build -buildmode=plugin -ldflags "-X main.Version=1.2.3" -o checker-email-keys.so ./plugin
|
||||
var Version = "custom-build"
|
||||
|
||||
// NewCheckerPlugin is the symbol resolved by happyDomain when loading
|
||||
// the .so file.
|
||||
func NewCheckerPlugin() (*sdk.CheckerDefinition, sdk.ObservationProvider, error) {
|
||||
openpgpkey.Version = Version
|
||||
return openpgpkey.Definition(), openpgpkey.Provider(), nil
|
||||
emailkeys.Version = Version
|
||||
return emailkeys.Definition(), emailkeys.Provider(), nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue