Skip to content
1 change: 1 addition & 0 deletions certloader/acmetlsconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type ACMEConfig struct {
MaxAttempts int
}

// TLSConfigSourceFromACME creates a TLSConfigSource that obtains certificates via ACME.
func TLSConfigSourceFromACME(acme *ACMEConfig) (TLSConfigSource, error) {
certmagic.DefaultACME.DisableHTTPChallenge = true
certmagic.DefaultACME.Agreed = acme.TOSAgreed
Expand Down
2 changes: 1 addition & 1 deletion certloader/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func readDERBlocks(reader io.Reader) ([]*pem.Block, error) {
return blocks, nil
}

return nil, fmt.Errorf("unable to parse DER data as X.509 (%v) or PKCS7 (%v)", err0, err1)
return nil, fmt.Errorf("unable to parse DER data as X.509 (%w) or PKCS7 (%w)", err0, err1)
}

func readPKCS12Blocks(reader io.Reader, password string) ([]*pem.Block, error) {
Expand Down
6 changes: 3 additions & 3 deletions certloader/jceks/modutf8.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func readModifiedUTF8(r io.Reader) (string, error) {
var err error
buf[0], err = br.ReadByte()
if err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
break
}

Expand All @@ -70,7 +70,7 @@ func readModifiedUTF8(r io.Reader) (string, error) {

buf[1], err = br.ReadByte()
if err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
err = io.ErrUnexpectedEOF
}

Expand All @@ -97,7 +97,7 @@ func readModifiedUTF8(r io.Reader) (string, error) {

buf[2], err = br.ReadByte()
if err != nil {
if err == io.EOF {
if errors.Is(err, io.EOF) {
err = io.ErrUnexpectedEOF
}

Expand Down
4 changes: 2 additions & 2 deletions certloader/tlsconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ type TLSConfigSource interface {

// GetServerConfig returns a TLSServerConfig interface that can be used to
// obtain TLS server configuration. The base configuration is cloned and
// used as a base for all returned TLS configuration. If the TLSConfig is
// not appropriate for use as a server, false is returned.
// used as a base for all returned TLS configuration. If the source is
// not appropriate for use as a server, an error is returned.
GetServerConfig(base *tls.Config) (TLSServerConfig, error)
}

Expand Down
56 changes: 39 additions & 17 deletions certstore/certstore_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
"fmt"
"io"
"log"
"sync"
"sync/atomic"
"unsafe"
)

Expand Down Expand Up @@ -117,9 +119,10 @@ func (s macStore) Close() {}

// macIdentity implements the Identity interface.
type macIdentity struct {
mu sync.Mutex
ref C.SecIdentityRef
kref C.SecKeyRef
cref C.SecCertificateRef
kref atomic.Uintptr
cref atomic.Uintptr
crt *x509.Certificate
chain []*x509.Certificate
}
Expand Down Expand Up @@ -158,6 +161,7 @@ func (i *macIdentity) CertificateChain() ([]*x509.Certificate, error) {
}

policy := C.SecPolicyCreateSSL(0, nilCFStringRef)
defer C.CFRelease(C.CFTypeRef(policy))

var trustRef C.SecTrustRef
if err := osStatusError(C.SecTrustCreateWithCertificates(C.CFTypeRef(certRef), C.CFTypeRef(policy), &trustRef)); err != nil {
Expand All @@ -170,6 +174,9 @@ func (i *macIdentity) CertificateChain() ([]*x509.Certificate, error) {
// us if the chain isn't trusted by the underlying system.
var cerr C.CFErrorRef
C.SecTrustEvaluateWithError(trustRef, &cerr)
if cerr != nilCFErrorRef {
C.CFRelease(C.CFTypeRef(cerr))
}

var (
nchain = C.SecTrustGetCertificateCount(trustRef)
Expand Down Expand Up @@ -237,19 +244,20 @@ func (i *macIdentity) Delete() error {

// Close implements the Identity interface.
func (i *macIdentity) Close() {
i.mu.Lock()
defer i.mu.Unlock()

if i.ref != nilSecIdentityRef {
C.CFRelease(C.CFTypeRef(i.ref))
i.ref = nilSecIdentityRef
}

if i.kref != nilSecKeyRef {
C.CFRelease(C.CFTypeRef(i.kref))
i.kref = nilSecKeyRef
if kref := C.SecKeyRef(i.kref.Swap(uintptr(nilSecKeyRef))); kref != nilSecKeyRef {
C.CFRelease(C.CFTypeRef(kref))
}

if i.cref != nilSecCertificateRef {
C.CFRelease(C.CFTypeRef(i.cref))
i.cref = nilSecCertificateRef
if cref := C.SecCertificateRef(i.cref.Swap(uintptr(nilSecCertificateRef))); cref != nilSecCertificateRef {
C.CFRelease(C.CFTypeRef(cref))
}
}

Expand Down Expand Up @@ -378,36 +386,50 @@ func (i *macIdentity) getAlgo(hash crypto.Hash, opts crypto.SignerOpts) (algo C.
return
}

// getKeyRef gets the SecKeyRef for this identity's pricate key.
// getKeyRef gets the SecKeyRef for this identity's private key.
func (i *macIdentity) getKeyRef() (C.SecKeyRef, error) {
if i.kref != nilSecKeyRef {
return i.kref, nil
if kref := C.SecKeyRef(i.kref.Load()); kref != nilSecKeyRef {
return kref, nil
}

i.mu.Lock()
defer i.mu.Unlock()

if kref := C.SecKeyRef(i.kref.Load()); kref != nilSecKeyRef {
return kref, nil
}

var keyRef C.SecKeyRef
if err := osStatusError(C.SecIdentityCopyPrivateKey(i.ref, &keyRef)); err != nil {
return nilSecKeyRef, err
}

i.kref = keyRef
i.kref.Store(uintptr(keyRef))

return i.kref, nil
return keyRef, nil
}

// getCertRef gets the SecCertificateRef for this identity's certificate.
func (i *macIdentity) getCertRef() (C.SecCertificateRef, error) {
if i.cref != nilSecCertificateRef {
return i.cref, nil
if cref := C.SecCertificateRef(i.cref.Load()); cref != nilSecCertificateRef {
return cref, nil
}

i.mu.Lock()
defer i.mu.Unlock()

if cref := C.SecCertificateRef(i.cref.Load()); cref != nilSecCertificateRef {
return cref, nil
}

var certRef C.SecCertificateRef
if err := osStatusError(C.SecIdentityCopyCertificate(i.ref, &certRef)); err != nil {
return nilSecCertificateRef, err
}

i.cref = certRef
i.cref.Store(uintptr(certRef))

return i.cref, nil
return certRef, nil
}

// exportCertRef gets a *x509.Certificate for the given SecCertificateRef.
Expand Down
2 changes: 1 addition & 1 deletion policy/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"github.com/open-policy-agent/opa/v1/rego"
)

// Policy wraps a OPA policy and supports reloading at runtime.
// Policy wraps an OPA policy and supports reloading at runtime.
type Policy interface {
// Reload will reload the policy. Subsequent calls to Evaluate will run
// the newly loaded policy, if reloading was successful. If reloading fails,
Expand Down
20 changes: 15 additions & 5 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,21 @@ def check_keytool():
print("keytool not available", file=sys.stderr)
sys.exit(2)

def skip_on_windows(reason="not supported on Windows"):
"""Skip the test on Windows."""
if IS_WINDOWS:
print(reason, file=sys.stderr)
sys.exit(2)
def require_platform(*platforms):
"""Skip the test unless running on one of the specified platforms.

Platform names match platform.system() output: 'Darwin', 'Linux', 'Windows'.
The special name 'BSD' matches any platform ending in 'BSD'
(e.g. FreeBSD, OpenBSD, NetBSD).
"""
current = platform.system()
if current in platforms:
return
if 'BSD' in platforms and current.endswith('BSD'):
return
print("skipped: requires {0} (running on {1})".format(
'/'.join(platforms), current), file=sys.stderr)
sys.exit(2)

def reload_args():
"""Extra args to enable certificate reload on Windows via --timed-reload."""
Expand Down
4 changes: 2 additions & 2 deletions tests/test-client-handles-client-closes-connection-unix.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
Ensures when client disconnects that the server connection also disconnects, with UNIX sockets.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixClient, TlsServer, print_ok, run_ghostunnel, skip_on_windows, terminate, TARGET_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixClient, TlsServer, print_ok, run_ghostunnel, require_platform, terminate, TARGET_PORT

skip_on_windows("requires Unix sockets")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None
try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test-client-handles-server-closes-connection-unix.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
Ensures when server disconnects that the client connection also disconnects, with UNIX sockets.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixClient, TlsServer, print_ok, run_ghostunnel, skip_on_windows, terminate, TARGET_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixClient, TlsServer, print_ok, run_ghostunnel, require_platform, terminate, TARGET_PORT

skip_on_windows("requires Unix sockets")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None
try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test-client-launchd-socket-activation-error.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
Spins up a client and tests systemd socket activation.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, print_ok, run_ghostunnel, skip_on_windows, terminate
from common import LOCALHOST, RootCert, STATUS_PORT, print_ok, run_ghostunnel, require_platform, terminate

skip_on_windows("requires launchd")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None

Expand Down
Empty file modified tests/test-client-listen-port-conflict.py
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions tests/test-client-shutdown-sigterm.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env python3

from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, TcpClient, TlsClient, TlsServer, print_ok, run_ghostunnel, skip_on_windows, terminate, LISTEN_PORT, TARGET_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, TcpClient, TlsClient, TlsServer, print_ok, run_ghostunnel, require_platform, terminate, LISTEN_PORT, TARGET_PORT
import time
import os

skip_on_windows("SIGTERM not supported")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None
try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test-client-shutdown-timeout.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env python3

from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, TcpClient, TlsClient, TlsServer, print_ok, run_ghostunnel, skip_on_windows, terminate, LISTEN_PORT, TARGET_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, TcpClient, TlsClient, TlsServer, print_ok, run_ghostunnel, require_platform, terminate, LISTEN_PORT, TARGET_PORT
import time
import os

skip_on_windows("SIGTERM not supported")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None
try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test-client-systemd-socket-activation-error.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
Spins up a client and tests systemd socket activation.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, print_ok, run_ghostunnel, skip_on_windows, terminate
from common import LOCALHOST, RootCert, STATUS_PORT, print_ok, run_ghostunnel, require_platform, terminate

skip_on_windows("requires systemd")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None

Expand Down
4 changes: 2 additions & 2 deletions tests/test-client-systemd-socket-activation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
Spins up a client and tests systemd socket activation.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, TcpClient, print_ok, run_ghostunnel, skip_on_windows, terminate, LISTEN_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, TcpClient, print_ok, run_ghostunnel, require_platform, terminate, LISTEN_PORT
from shutil import which
import sys

skip_on_windows("requires systemd")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None

Expand Down
4 changes: 2 additions & 2 deletions tests/test-client-unix-socket-backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
Ensures ghostunnel can listen on a unix socket.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, TlsServer, UnixClient, print_ok, run_ghostunnel, skip_on_windows, terminate, TARGET_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, TlsServer, UnixClient, print_ok, run_ghostunnel, require_platform, terminate, TARGET_PORT
import os
import os.path

skip_on_windows("requires Unix sockets")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None
try:
Expand Down
Empty file modified tests/test-client-verify-cn.py
100644 → 100755
Empty file.
Empty file modified tests/test-client-verify-ou.py
100644 → 100755
Empty file.
Empty file modified tests/test-server-allow-all.py
100644 → 100755
Empty file.
4 changes: 2 additions & 2 deletions tests/test-server-handles-client-closes-connection-unix.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
Ensures when client disconnects that the server connection also disconnects, with UNIX sockets.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixServer, TlsClient, print_ok, run_ghostunnel, skip_on_windows, terminate, LISTEN_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixServer, TlsClient, print_ok, run_ghostunnel, require_platform, terminate, LISTEN_PORT

skip_on_windows("requires Unix sockets")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None
try:
Expand Down
4 changes: 2 additions & 2 deletions tests/test-server-handles-server-closes-connection-unix.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
Ensures when server disconnects that the client connection also disconnects, with UNIX sockets.
"""

from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixServer, TlsClient, print_ok, run_ghostunnel, skip_on_windows, terminate, LISTEN_PORT
from common import LOCALHOST, RootCert, STATUS_PORT, SocketPair, UnixServer, TlsClient, print_ok, run_ghostunnel, require_platform, terminate, LISTEN_PORT

skip_on_windows("requires Unix sockets")
require_platform('Darwin', 'Linux', 'BSD')

ghostunnel = None
try:
Expand Down
Empty file modified tests/test-server-invalid-uri-pattern.py
100644 → 100755
Empty file.
Loading
Loading