Skip to content

Commit aa784a9

Browse files
committed
device: add new handshake handler and keylog writer
This change adds support for a new environment variable 'WG_KEYLOGFILE' in resemblance to the 'SSLKEYLOGFILE' environment variable used by curl, Chrome & Firefox to log ephemeral TLS encryption keys When set, wireguard-go will log ephemeral keys generated during each handshake to a file specified by the environment variable in the WireGuard key log format. The format used is the same as then one generated by the extract-handshakes.sh script. See also: - https://git.zx2c4.com/wireguard-tools/tree/contrib/extract-handshakes - https://wiki.wireshark.org/WireGuard#key-log-format - https://everything.curl.dev/usingcurl/tls/sslkeylogfile Signed-off-by: Steffen Vogel <[email protected]>
1 parent c31a7b1 commit aa784a9

File tree

5 files changed

+82
-5
lines changed

5 files changed

+82
-5
lines changed

device/device.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
package device
77

88
import (
9+
"encoding/base64"
10+
"fmt"
11+
"io"
912
"runtime"
1013
"sync"
1114
"sync/atomic"
@@ -17,6 +20,8 @@ import (
1720
"golang.zx2c4.com/wireguard/tun"
1821
)
1922

23+
type HandshakeHandler func(t time.Time, ls NoisePrivateKey, rs NoisePublicKey, le NoisePrivateKey, ps NoisePresharedKey)
24+
2025
type Device struct {
2126
state struct {
2227
// state holds the device's state. It is accessed atomically.
@@ -85,6 +90,8 @@ type Device struct {
8590
mtu int32
8691
}
8792

93+
keyLogHandler HandshakeHandler
94+
8895
ipcMutex sync.RWMutex
8996
closed chan struct{}
9097
log *Logger
@@ -94,10 +101,9 @@ type Device struct {
94101
// There are three states: down, up, closed.
95102
// Transitions:
96103
//
97-
// down -----+
98-
// ↑↓ ↓
99-
// up -> closed
100-
//
104+
// down -----+
105+
// ↑↓ ↓
106+
// up -> closed
101107
type deviceState uint32
102108

103109
//go:generate go run golang.org/x/tools/cmd/stringer -type deviceState -trimprefix=deviceState
@@ -523,3 +529,26 @@ func (device *Device) BindClose() error {
523529
device.net.Unlock()
524530
return err
525531
}
532+
533+
func (device *Device) OnHandshake(hdlr HandshakeHandler) {
534+
device.keyLogHandler = hdlr
535+
}
536+
537+
func (device *Device) WriteKeyLog(wr io.Writer) {
538+
mu := sync.Mutex{}
539+
540+
device.OnHandshake(func(t time.Time, ls NoisePrivateKey, rs NoisePublicKey, le NoisePrivateKey, ps NoisePresharedKey) {
541+
mu.Lock()
542+
defer mu.Unlock()
543+
544+
fmt.Fprintf(wr, "LOCAL_STATIC_PRIVATE_KEY=%s\n", base64.StdEncoding.EncodeToString(ls[:]))
545+
fmt.Fprintf(wr, "REMOTE_STATIC_PUBLIC_KEY=%s\n", base64.StdEncoding.EncodeToString(rs[:]))
546+
fmt.Fprintf(wr, "LOCAL_EPHEMERAL_PRIVATE_KEY=%s\n", base64.StdEncoding.EncodeToString(le[:]))
547+
548+
if !ps.IsZero() {
549+
fmt.Fprintf(wr, "PRESHARED_KEY=%s\n", base64.StdEncoding.EncodeToString(ps[:]))
550+
}
551+
552+
device.log.Verbosef("Writing new ephemeral key to keylog")
553+
})
554+
}

device/noise-protocol.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ func (device *Device) CreateMessageInitiation(peer *Peer) (*MessageInitiation, e
243243

244244
handshake.mixHash(msg.Timestamp[:])
245245
handshake.state = handshakeInitiationCreated
246+
247+
if device.keyLogHandler != nil {
248+
go device.keyLogHandler(handshake.lastTimestamp.Time(), device.staticIdentity.privateKey, handshake.remoteStatic, handshake.localEphemeral, handshake.presharedKey)
249+
}
250+
246251
return &msg, nil
247252
}
248253

@@ -414,6 +419,10 @@ func (device *Device) CreateMessageResponse(peer *Peer) (*MessageResponse, error
414419

415420
handshake.state = handshakeResponseCreated
416421

422+
if device.keyLogHandler != nil {
423+
go device.keyLogHandler(handshake.lastTimestamp.Time(), device.staticIdentity.privateKey, handshake.remoteStatic, handshake.localEphemeral, handshake.presharedKey)
424+
}
425+
417426
return &msg, nil
418427
}
419428

device/noise-types.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,12 @@ func (key NoisePublicKey) Equals(tar NoisePublicKey) bool {
7676
func (key *NoisePresharedKey) FromHex(src string) error {
7777
return loadExactHex(key[:], src)
7878
}
79+
80+
func (key NoisePresharedKey) Equals(tar NoisePresharedKey) bool {
81+
return subtle.ConstantTimeCompare(key[:], tar[:]) == 1
82+
}
83+
84+
func (key NoisePresharedKey) IsZero() bool {
85+
var zero NoisePresharedKey
86+
return key.Equals(zero)
87+
}

main.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const (
3030
ENV_WG_TUN_FD = "WG_TUN_FD"
3131
ENV_WG_UAPI_FD = "WG_UAPI_FD"
3232
ENV_WG_PROCESS_FOREGROUND = "WG_PROCESS_FOREGROUND"
33+
ENV_WG_KEYLOG = "WG_KEYLOGFILE"
3334
)
3435

3536
func printUsage() {
@@ -152,6 +153,22 @@ func main() {
152153
os.Exit(ExitSetupFailed)
153154
}
154155

156+
// open keylog file
157+
158+
keyLog, err := func() (*os.File, error) {
159+
fn := os.Getenv(ENV_WG_KEYLOG)
160+
if fn == "" {
161+
return nil, nil
162+
}
163+
164+
return os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
165+
}()
166+
if err != nil {
167+
logger.Errorf("failed to open keylog error: %v", err)
168+
os.Exit(ExitSetupFailed)
169+
return
170+
}
171+
155172
// open UAPI file (or use supplied fd)
156173

157174
fileUAPI, err := func() (*os.File, error) {
@@ -174,6 +191,7 @@ func main() {
174191
os.Exit(ExitSetupFailed)
175192
return
176193
}
194+
177195
// daemonize the process
178196

179197
if !foreground {
@@ -248,6 +266,14 @@ func main() {
248266

249267
logger.Verbosef("UAPI listener started")
250268

269+
// start writing handshakes to keylog file
270+
271+
if keyLog != nil {
272+
device.WriteKeyLog(keyLog)
273+
274+
logger.Verbosef("Keylog writer started")
275+
}
276+
251277
// wait for program to terminate
252278

253279
signal.Notify(term, syscall.SIGTERM)

tai64n/tai64n.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,9 @@ func (t1 Timestamp) After(t2 Timestamp) bool {
3737
}
3838

3939
func (t Timestamp) String() string {
40-
return time.Unix(int64(binary.BigEndian.Uint64(t[:8])-base), int64(binary.BigEndian.Uint32(t[8:12]))).String()
40+
return t.Time().String()
41+
}
42+
43+
func (t Timestamp) Time() time.Time {
44+
return time.Unix(int64(binary.BigEndian.Uint64(t[:8])-base), int64(binary.BigEndian.Uint32(t[8:12])))
4145
}

0 commit comments

Comments
 (0)