Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tlsconfig: Add support for configuring use of PQ KEMs during TLS handshake #294

Closed
wants to merge 3 commits into from
Closed
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
43 changes: 34 additions & 9 deletions .github/workflows/pr_build.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
name: PR Build
on:
push: {}
pull_request: {}
workflow_dispatch: {}
env:
GO_VERSION: 1.21
GOTOOLCHAIN: local
jobs:
lint-linux:
strategy:
matrix:
go-version:
- setup: "1.21"
makeArgs: ""
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -15,11 +21,18 @@ jobs:
with:
cache: true
cache-dependency-path: v2/go.sum
go-version: ${{ env.GO_VERSION }}
go-version: ${{ matrix.go-version.setup }}
- name: Lint
run: make lint
run: make lint ${{ matrix.go-version.makeArgs }}

test-linux:
strategy:
matrix:
go-version:
- setup: "1.21"
makeArgs: ""
- setup: "1.23.0-rc.2"
makeArgs: "go_version_full=1.23rc2"
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -29,11 +42,16 @@ jobs:
with:
cache: true
cache-dependency-path: v2/go.sum
go-version: ${{ env.GO_VERSION }}
go-version: ${{ matrix.go-version.setup }}
- name: Test
run: make test
run: make test ${{ matrix.go-version.makeArgs }}

lint-windows:
strategy:
matrix:
go-version:
- setup: "1.21"
makeArgs: ""
runs-on: windows-2022
defaults:
run:
Expand All @@ -46,7 +64,7 @@ jobs:
with:
cache: true
cache-dependency-path: v2/go.sum
go-version: ${{ env.GO_VERSION }}
go-version: ${{ matrix.go-version.setup }}
- name: Install msys2
uses: msys2/setup-msys2@v2
with:
Expand All @@ -58,9 +76,16 @@ jobs:
mingw-w64-x86_64-toolchain
unzip
- name: Lint
run: make lint
run: make lint ${{ matrix.go-version.makeArgs }}

test-windows:
strategy:
matrix:
go-version:
- setup: "1.21"
makeArgs: ""
- setup: "1.23.0-rc.2"
makeArgs: "go_version_full=1.23rc2"
runs-on: windows-2022
defaults:
run:
Expand All @@ -73,7 +98,7 @@ jobs:
with:
cache: true
cache-dependency-path: v2/go.sum
go-version: ${{ env.GO_VERSION }}
go-version: ${{ matrix.go-version.setup }}
- name: Install msys2
uses: msys2/setup-msys2@v2
with:
Expand All @@ -85,7 +110,7 @@ jobs:
mingw-w64-x86_64-toolchain
unzip
- name: Test
run: make test
run: make test ${{ matrix.go-version.makeArgs }}

# This job is just here to make sure that the other jobs have completed
# and is used as a single job to block PR merge from. GH doesn't have a
Expand Down
83 changes: 82 additions & 1 deletion v2/spiffetls/tlsconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func HookTLSClientConfig(config *tls.Config, bundle x509bundle.Source, authorize
resetAuthFields(config)
config.InsecureSkipVerify = true
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
applyOptions(config, opts)
}

// A Option changes the defaults used to by mTLS ClientConfig functions.
Expand All @@ -36,7 +37,8 @@ type option func(*options)
func (fn option) apply(o *options) { fn(o) }

type options struct {
trace Trace
trace Trace
pqKemMode PQKEMMode
}

func newOptions(opts []Option) *options {
Expand All @@ -55,6 +57,38 @@ func WithTrace(trace Trace) Option {
})
}

// Post-quantum TLS KEM mode. Determines whether a post-quantum safe KEM should
// be used when establishing a TLS connection.
type PQKEMMode int

const (
// Do not require use of a post-quantum KEM when establishing a TLS
// connection. Whether a post-quantum KEM is attempted depends on
// environmental configuration (e.g. GODEBUG setting tlskyber) and the target
// Go version at build time.
PQKEMModeDefault PQKEMMode = iota

// Attempt use of a post-quantum KEM as the most preferred key exchange
// method when establishing a TLS connection.
// Support for this requires Go 1.23 or later.
// Configuring this will cause connections to fail if support is not available.
PQKEMModeAttempt

// Require use of a post-quantum KEM when establishing a TLS connection.
// Attempts to initiate a connection with a key exchange method which is not
// post-quantum safe will fail. Support for this requires Go 1.23 or later.
// Configuring this will cause connections to fail if support is not available.
PQKEMModeRequire
)

// WithPQKEMMode configures whether a post-quantum safe KEM should be used when
// establishing a TLS connection.
func WithPQKEMMode(mode PQKEMMode) Option {
return option(func(opts *options) {
opts.pqKemMode = mode
})
}

// MTLSClientConfig returns a TLS configuration which presents an X509-SVID
// to the server and verifies and authorizes the server X509-SVID.
func MTLSClientConfig(svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) *tls.Config {
Expand All @@ -72,6 +106,7 @@ func HookMTLSClientConfig(config *tls.Config, svid x509svid.Source, bundle x509b
config.GetClientCertificate = GetClientCertificate(svid, opts...)
config.InsecureSkipVerify = true
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
applyOptions(config, opts)
}

// MTLSWebClientConfig returns a TLS configuration which presents an X509-SVID
Expand All @@ -90,6 +125,7 @@ func HookMTLSWebClientConfig(config *tls.Config, svid x509svid.Source, roots *x5
resetAuthFields(config)
config.GetClientCertificate = GetClientCertificate(svid, opts...)
config.RootCAs = roots
applyOptions(config, opts)
}

// TLSServerConfig returns a TLS configuration which presents an X509-SVID
Expand All @@ -105,6 +141,7 @@ func TLSServerConfig(svid x509svid.Source, opts ...Option) *tls.Config {
func HookTLSServerConfig(config *tls.Config, svid x509svid.Source, opts ...Option) {
resetAuthFields(config)
config.GetCertificate = GetCertificate(svid, opts...)
applyOptions(config, opts)
}

// MTLSServerConfig returns a TLS configuration which presents an X509-SVID
Expand All @@ -125,6 +162,7 @@ func HookMTLSServerConfig(config *tls.Config, svid x509svid.Source, bundle x509b
config.ClientAuth = tls.RequireAnyClientCert
config.GetCertificate = GetCertificate(svid, opts...)
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
applyOptions(config, opts)
}

// MTLSWebServerConfig returns a TLS configuration which presents a web
Expand All @@ -146,6 +184,7 @@ func HookMTLSWebServerConfig(config *tls.Config, cert *tls.Certificate, bundle x
config.ClientAuth = tls.RequireAnyClientCert
config.Certificates = []tls.Certificate{*cert}
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
applyOptions(config, opts)
}

// GetCertificate returns a GetCertificate callback for tls.Config. It uses the
Expand Down Expand Up @@ -252,3 +291,45 @@ func resetAuthFields(config *tls.Config) {
config.NameToCertificate = nil //nolint:staticcheck // setting to nil is OK
config.RootCAs = nil
}

// Not exported by crypto/tls, so we define it here from the I-D.
const x25519Kyber768Draft00 tls.CurveID = 0x6399

func applyOptions(config *tls.Config, opts []Option) {
o := newOptions(opts)

// Apply post-quantum KEM mode option.
switch o.pqKemMode {
case PQKEMModeDefault:
// Nothing to do - allow default curve preferences.

case PQKEMModeAttempt:
if len(config.CurvePreferences) == 0 {
// This is copied from the crypto/tls default curve list.
config.CurvePreferences = []tls.CurveID{
x25519Kyber768Draft00,
tls.X25519,
tls.CurveP256,
tls.CurveP384,
tls.CurveP521,
}
} else if config.CurvePreferences[0] != x25519Kyber768Draft00 {
// Prepend X25519Kyber768Draft00 to the list, making it most preferred.
curves := make([]tls.CurveID, 0, len(config.CurvePreferences)+1)
curves = append(curves, x25519Kyber768Draft00)
curves = append(curves, config.CurvePreferences...)
config.CurvePreferences = curves
}

case PQKEMModeRequire:
// List only known PQ-safe KEMs as valid curves.
config.CurvePreferences = []tls.CurveID{
x25519Kyber768Draft00,
}

// Require TLS 1.3, as all PQ-safe KEMs require it anyway.
if config.MinVersion < tls.VersionTLS13 {
config.MinVersion = tls.VersionTLS13
}
}
}
Loading