Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ services:
- .:/boulder:cached
- ./.gocache:/root/.cache/go-build:cached
- ./test/certs/.softhsm-tokens/:/var/lib/softhsm/tokens/:cached
- pkimetal-socket:/var/run/pkimetal
networks:
bouldernet:
ipv4_address: 10.77.77.77
Expand Down Expand Up @@ -141,7 +142,11 @@ services:
- bouldernet

bpkimetal:
image: ghcr.io/pkimetal/pkimetal:v1.20.0
image: ghcr.io/pkimetal/pkimetal:v1.32.0
user: root
volumes:
- pkimetal-socket:/var/run/pkimetal
- ./test/config/pkimetal.yaml:/app/config.yaml:ro
networks:
- bouldernet

Expand Down Expand Up @@ -208,3 +213,6 @@ networks:
driver: default
config:
- subnet: 64.112.117.128/25

volumes:
pkimetal-socket:
37 changes: 33 additions & 4 deletions linter/lints/rfc/lint_cert_via_pkimetal.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (
"encoding/json"
"fmt"
"io"
"net"
"net/http"
"net/url"
"slices"
"strings"
"sync"
"time"

"github.com/zmap/zcrypto/x509"
Expand All @@ -21,9 +23,13 @@ import (
// both certs and CRLs using PKIMetal.
type PKIMetalConfig struct {
Addr string `toml:"addr" comment:"The address where a pkilint REST API can be reached."`
Socket string `toml:"socket" comment:"The Unix socket path where a pkilint REST API can be reached. If set, this takes precedence over Addr."`
Severity string `toml:"severity" comment:"The minimum severity of findings to report (meta, debug, info, notice, warning, error, bug, or fatal)."`
Timeout time.Duration `toml:"timeout" comment:"How long, in nanoseconds, to wait before giving up."`
IgnoreLints []string `toml:"ignore_lints" comment:"The unique Validator:Code IDs of lint findings which should be ignored."`

client *http.Client
clientOnce sync.Once
}

func (pkim *PKIMetalConfig) execute(endpoint string, der []byte) (*lint.LintResult, error) {
Expand All @@ -32,10 +38,33 @@ func (pkim *PKIMetalConfig) execute(endpoint string, der []byte) (*lint.LintResu
timeout = 100 * time.Millisecond
}

// Initialize HTTP client once with thread-safe sync.Once for connection pooling
pkim.clientOnce.Do(func() {
pkim.client = &http.Client{}
// If using Unix socket, set up custom transport
if pkim.Socket != "" {
pkim.client.Transport = &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, "unix", pkim.Socket)
},
}
}
})

ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()

apiURL, err := url.JoinPath(pkim.Addr, endpoint)
// Determine the base URL: use localhost for Unix sockets, otherwise use configured address
var baseURL string
if pkim.Socket != "" {
// For Unix sockets, the hostname is ignored since the custom DialContext
// overrides the connection mechanism to use the socket path.
baseURL = "http://localhost"
} else {
baseURL = pkim.Addr
}

apiURL, err := url.JoinPath(baseURL, endpoint)
if err != nil {
return nil, fmt.Errorf("constructing pkimetal url: %w", err)
}
Expand All @@ -56,7 +85,7 @@ func (pkim *PKIMetalConfig) execute(endpoint string, der []byte) (*lint.LintResu
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Accept", "application/json")

resp, err := http.DefaultClient.Do(req)
resp, err := pkim.client.Do(req)
if err != nil {
return nil, fmt.Errorf("making POST request to pkimetal API: %s (timeout %s)", err, timeout)
}
Expand Down Expand Up @@ -141,8 +170,8 @@ func (l *certViaPKIMetal) Configure() any {

func (l *certViaPKIMetal) CheckApplies(c *x509.Certificate) bool {
// This lint applies to all certificates issued by Boulder, as long as it has
// been configured with an address to reach out to. If not, skip it.
return l.Addr != ""
// been configured with an address or socket to reach out to. If not, skip it.
return l.Addr != "" || l.Socket != ""
}

func (l *certViaPKIMetal) Execute(c *x509.Certificate) *lint.LintResult {
Expand Down
4 changes: 2 additions & 2 deletions linter/lints/rfc/lint_crl_via_pkimetal.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ func (l *crlViaPKIMetal) Configure() any {

func (l *crlViaPKIMetal) CheckApplies(c *x509.RevocationList) bool {
// This lint applies to all CRLs issued by Boulder, as long as it has
// been configured with an address to reach out to. If not, skip it.
return l.Addr != ""
// been configured with an address or socket to reach out to. If not, skip it.
return l.Addr != "" || l.Socket != ""
}

func (l *crlViaPKIMetal) Execute(c *x509.RevocationList) *lint.LintResult {
Expand Down
2 changes: 2 additions & 0 deletions test/config-next/pkimetal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
server:
webserverPath: /var/run/pkimetal/pkimetal.sock
4 changes: 2 additions & 2 deletions test/config-next/zlint.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[e_pkimetal_lint_cabf_serverauth_cert]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = [
Expand All @@ -22,7 +22,7 @@ ignore_lints = [
]

[e_pkimetal_lint_cabf_serverauth_crl]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = []
2 changes: 2 additions & 0 deletions test/config/pkimetal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
server:
webserverPath: /var/run/pkimetal/pkimetal.sock
4 changes: 2 additions & 2 deletions test/config/zlint.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[e_pkimetal_lint_cabf_serverauth_cert]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = [
Expand All @@ -18,7 +18,7 @@ ignore_lints = [
]

[e_pkimetal_lint_cabf_serverauth_crl]
addr = "http://bpkimetal:8080"
socket = "/var/run/pkimetal/pkimetal.sock"
severity = "notice"
timeout = 2000000000 # 2 seconds
ignore_lints = []
Loading