Documentation
¶
Overview ¶
Package skynetca pkg/skynetca/ca.go c4-app-skynet authority used by the skywire resolver to terminate TLS for `*.skynet`, `*.dmsg` and `*.skysocks` hostnames in the visitor's browser.
The CA is generated on the visitor's machine, name-constrained via the X.509 nameConstraints extension to the resolver TLDs, and installed into the OS trust store. Cross-wire authentication is already provided by the underlying skywire transport (Noise + secp256k1 visor pubkey); the locally-issued leaf cert exists only to satisfy the browser's secure-context requirements.
The package exports three primitives:
- CA lifecycle on disk: GenerateCA / SaveCA / LoadCA / Fingerprint.
- LeafMinter: on-demand leaf cert minting and caching, signed by the CA.
- MITMTerminate: TLS-termination splice that wraps an upstream net.Conn and returns a net.Conn the resolver's SOCKS5 server can splice against.
pkg/skynetweb and pkg/dmsgweb both consume this package; neither imports the other.
Package skynetca pkg/skynetca/leaf.go c4-app-skynet
Package skynetca pkg/skynetca/mitm.go c4-app-skynet
Index ¶
- Constants
- Variables
- func Fingerprint(cert *x509.Certificate) string
- func GenerateCA(opts CAOptions) (*x509.Certificate, *ecdsa.PrivateKey, error)
- func LoadCA(certPath, keyPath string) (*x509.Certificate, *ecdsa.PrivateKey, error)
- func MITMTerminate(upstream net.Conn, leaf *tls.Certificate) net.Conn
- func Permits(m LeafMinter, host string) bool
- func SaveCA(cert *x509.Certificate, key *ecdsa.PrivateKey, certPath, keyPath string) error
- type CAOptions
- type CachedMinter
- type HostPermitter
- type IPMinter
- type LeafMinter
- type LeafOptions
Constants ¶
const PermittedIPRange = "198.18.0.0/15"
PermittedIPRange is the only range a constrained CA may name by IP. It is SkyDNS's range (skydns.Range), which holds the resolver's DoH address.
Variables ¶
var DefaultPermittedDomains = []string{".skynet", ".dmsg", ".skysocks"}
DefaultPermittedDomains is the set of TLDs the resolver CA is allowed to issue leaf certs for. The leading dot means "any subdomain of"; bare TLDs themselves are not matched.
Functions ¶
func Fingerprint ¶
func Fingerprint(cert *x509.Certificate) string
Fingerprint returns the SHA-256 fingerprint of cert in the conventional colon-separated lowercase hex format.
func GenerateCA ¶
func GenerateCA(opts CAOptions) (*x509.Certificate, *ecdsa.PrivateKey, error)
GenerateCA returns a fresh ECDSA P-256 CA suitable for signing leaf certs. Name constraints are applied per opts.PermittedDomains, unless opts.Unconstrained is set (no nameConstraints at all).
func LoadCA ¶
func LoadCA(certPath, keyPath string) (*x509.Certificate, *ecdsa.PrivateKey, error)
LoadCA reads a CA cert + key pair previously written by SaveCA.
func MITMTerminate ¶
MITMTerminate accepts an upstream net.Conn (the skywire transport to a merchant visor's plaintext HTTP server) and returns a net.Conn the caller (typically a SOCKS5 server's Dial callback) can splice against the browser.
Internally:
- A net.Pipe is created.
- One end is returned to the caller.
- The other end is wrapped in tls.Server with leaf and the TLS handshake is run with the browser via the pipe.
- After handshake, plaintext is spliced bidirectionally between the tls.Conn and upstream.
On any failure (handshake error, splice error, upstream close) all resources are released. The function returns immediately; the splice runs on a background goroutine. The caller must close the returned net.Conn when done; this triggers teardown of the goroutine and the upstream conn.
func Permits ¶
func Permits(m LeafMinter, host string) bool
Permits reports whether m can mint a leaf for host. A LeafMinter that implements HostPermitter is asked directly; any other implementation is treated optimistically (the mint itself still enforces its constraints). This keeps the check non-breaking — LeafMinter itself is unchanged.
func SaveCA ¶
func SaveCA(cert *x509.Certificate, key *ecdsa.PrivateKey, certPath, keyPath string) error
SaveCA writes cert and key to the given paths in PEM format. The key file is written 0600; the cert file 0644. The parent directory is created with 0700 if missing.
Types ¶
type CAOptions ¶
type CAOptions struct {
CommonName string
Validity time.Duration
PermittedDomains []string
// Unconstrained omits the X.509 nameConstraints extension entirely, so the CA
// can sign a leaf for ANY dnsName. This is the "forge any host" root a real
// clearnet HTTPS MITM (e.g. the skysocks-client HTTPS range-splitter) needs,
// and is a deliberate security decision: such a root must be created
// explicitly, never defaulted. PermittedDomains is ignored when this is set.
Unconstrained bool
}
CAOptions configures GenerateCA.
type CachedMinter ¶
type CachedMinter struct {
// contains filtered or unexported fields
}
CachedMinter is the default LeafMinter implementation. Leaves are regenerated on cache miss and when the cached cert's remaining lifetime falls below opts.RenewBefore.
func NewMinter ¶
func NewMinter(ca *x509.Certificate, caKey *ecdsa.PrivateKey, opts LeafOptions) *CachedMinter
NewMinter constructs a CachedMinter that signs leaves with the given CA. The CA must have been generated by GenerateCA (or be otherwise compatible — IsCA, KeyUsage with CertSign, name constraints set).
func (*CachedMinter) For ¶
func (m *CachedMinter) For(host string) (*tls.Certificate, error)
For returns a leaf cert valid for host. The returned cert is shared with other callers via the cache; do not mutate.
func (*CachedMinter) ForIP ¶
func (m *CachedMinter) ForIP(ip netip.Addr) (*tls.Certificate, error)
ForIP returns a leaf whose only name is ip, which must be in the CA's permitted IP ranges (RFC 5280 section 4.2.1.10).
func (*CachedMinter) Permits ¶
func (m *CachedMinter) Permits(host string) bool
Permits implements HostPermitter: it reports whether host falls under one of this minter's permitted suffixes, without minting or caching anything.
type HostPermitter ¶
HostPermitter is optionally implemented by a LeafMinter to report — WITHOUT attempting a mint — whether it can issue a leaf for host. Callers that decide whether to route a request down the TLS-MITM path (e.g. the resolving proxies' HTTPS interstitial) use this to skip hosts the name-constrained CA can't cover (arbitrary clearnet HTTPS), rather than calling For and logging its expected "does not match any permitted suffix" failure on every such request.
type IPMinter ¶
type IPMinter interface {
ForIP(ip netip.Addr) (*tls.Certificate, error)
}
IPMinter is optionally implemented by a LeafMinter that can also issue a leaf for an IP address, such as the one SkyDNS serves DNS over HTTPS on.
type LeafMinter ¶
type LeafMinter interface {
For(host string) (*tls.Certificate, error)
}
LeafMinter mints (and typically caches) leaf TLS certs signed by a local CA. Implementations must be safe for concurrent use.
func NewStaticMinter ¶
func NewStaticMinter(leaf *tls.Certificate) LeafMinter
NewStaticMinter returns a LeafMinter that always returns leaf. Intended for tests; production callers should use NewMinter.