func main() {
ourPrivate, _ := base64.StdEncoding.DecodeString("WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=")
ourPublic, _ := base64.StdEncoding.DecodeString("K5sF9yESrSBsOXPd6TcpKNgqoy1Ik3ZFKl4FolzrRyI=")
- preshared, _ := base64.StdEncoding.DecodeString("FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=")
theirPublic, _ := base64.StdEncoding.DecodeString("qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=")
+ preshared, _ := base64.StdEncoding.DecodeString("FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=")
cs := noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashBLAKE2s)
hs := noise.NewHandshakeState(noise.Config{
CipherSuite: cs,
Random: rand.Reader,
Pattern: noise.HandshakeIK,
Initiator: true,
- Prologue: []byte("WireGuard v0 zx2c4 Jason@zx2c4.com"),
+ Prologue: []byte("WireGuard v1 zx2c4 Jason@zx2c4.com"),
PresharedKey: preshared,
+ PresharedKeyPlacement: 2,
StaticKeypair: noise.DHKey{Private: ourPrivate, Public: ourPublic},
PeerStatic: theirPublic,
})
initiationPacket[3] = 0 // Reserved
binary.LittleEndian.PutUint32(initiationPacket[4:], 28) // Sender index: 28 (arbitrary)
initiationPacket, _, _ = hs.WriteMessage(initiationPacket, tai64n)
- hasher, _ := blake2s.New(&blake2s.Config{Size: 16, Key: preshared})
+ hasher, _ := blake2s.New(&blake2s.Config{Size: 32})
+ hasher.Write([]byte("mac1----"))
hasher.Write(theirPublic)
+ hasher, _ = blake2s.New(&blake2s.Config{Size: 16, Key: hasher.Sum(nil)})
hasher.Write(initiationPacket)
initiationPacket = append(initiationPacket, hasher.Sum(nil)[:16]...)
initiationPacket = append(initiationPacket, make([]byte, 16)...)
-> IO ()
w theirPub (Plaintext myPSK) sock addr msg = do
let x = "\x01\x00\x00\x00\x00\x00" `mappend` msg
- mac = hash 16 myPSK (sbToBS' (curvePubToBytes theirPub) `mappend` sbToBS' x)
+ mac = hash 16 myPSK (sbToBS' (curvePubToBytes theirPub) `mappend` sbToBS' x) -- TODO: this should actually be blake2s(key=blake2s("mac1----" || theirPub), payload=blah)
void $ NBS.sendTo sock (x `mappend` mac `mappend` replicate 16 '\0') addr
r :: MVar ByteString -> Socket -> IO ByteString
serverkey' = curveBytesToPub . bsToSB' . either undefined id . B64.decode . pack $ serverkey :: PublicKey Curve25519
psk' = Plaintext . bsToSB' . either undefined id . B64.decode . pack $ psk
hs = handshakeState $ HandshakeStateParams
- noiseIK
- "WireGuard v0 zx2c4 Jason@zx2c4.com"
+ noiseIK -- TODO: specify psk2 mode
+ "WireGuard v1 zx2c4 Jason@zx2c4.com"
(Just psk')
(Just mykey')
Nothing
owner.set_rs(&their_public);
let mut cipherstate1 : CipherState<CipherChaChaPoly> = Default::default();
let mut cipherstate2 : CipherState<CipherChaChaPoly> = Default::default();
- let mut handshake = HandshakeState::new_from_owner(&mut owner, true, HandshakePattern::IK, "WireGuard v0 zx2c4 Jason@zx2c4.com".as_bytes(), Some(&my_preshared[..]), &mut cipherstate1, &mut cipherstate2);
+ //TODO: specify psk2 mode
+ let mut handshake = HandshakeState::new_from_owner(&mut owner, true, HandshakePattern::IK, "WireGuard v1 zx2c4 Jason@zx2c4.com".as_bytes(), Some(&my_preshared[..]), &mut cipherstate1, &mut cipherstate2);
let now = time::get_time();
let mut tai64n = [0; 12];
- BigEndian::write_i64(&mut tai64n[0..], 4611686018427387914ULL + now.sec);
+ BigEndian::write_i64(&mut tai64n[0..], 4611686018427387914 + now.sec);
BigEndian::write_i32(&mut tai64n[8..], now.nsec);
let mut initiation_packet = [0; 148];
initiation_packet[0] = 1; /* Type: Initiation */
initiation_packet[3] = 0; /* Reserved */
LittleEndian::write_u32(&mut initiation_packet[4..], 28); /* Sender index: 28 (arbitrary) */
handshake.write_message(&tai64n, &mut initiation_packet[8..]);
- let mut mac_material = [0; 148];
- memcpy(&mut mac_material, &their_public);
- memcpy(&mut mac_material[32..], &initiation_packet[0..116]);
+ let mut mac_key_input = [0; 40];
+ let mut mac_key = [0; 32];
+ memcpy(&mut mac_key_input, b"mac1----");
+ memcpy(&mut mac_key_input[8..], &their_public);
+ Blake2s::blake2s(&mut mac_key, &mac_key_input, &[0; 0]);
let mut mac = [0; 16];
- Blake2s::blake2s(&mut mac, &mac_material, &my_preshared);
+ Blake2s::blake2s(&mut mac, &initiation_packet[0..116], &mac_key);
memcpy(&mut initiation_packet[116..], &mac);
socket.send_to(&initiation_packet, &send_addr).unwrap();
if [[ $device != "$last_device" ]]; then
[[ -z $last_device ]] && printf '\n' || printf '%s,\n' "$end"
last_device="$device"
- read -r private_key public_key preshared_key listen_port fwmark
+ read -r private_key public_key listen_port fwmark
printf '\t"%s": {' "$device"
delim=$'\n'
[[ $private_key == "(none)" ]] || { printf '%s\t\t"privateKey": "%s"' "$delim" "$private_key"; delim=$',\n'; }
[[ $public_key == "(none)" ]] || { printf '%s\t\t"publicKey": "%s"' "$delim" "$public_key"; delim=$',\n'; }
- [[ $preshared_key == "(none)" ]] || { printf '%s\t\t"presharedKey": "%s"' "$delim" "$preshared_key"; delim=$',\n'; }
[[ $listen_port == "0" ]] || { printf '%s\t\t"listenPort": %u' "$delim" $(( $listen_port )); delim=$',\n'; }
[[ $fwmark == "off" ]] || { printf '%s\t\t"fwmark": %u' "$delim" $(( $fwmark )); delim=$',\n'; }
printf '%s\t\t"peers": {' "$delim"; end=$'\n\t\t}\n\t}'
delim=$'\n'
else
- read -r public_key endpoint allowed_ips latest_handshake transfer_rx transfer_tx persistent_keepalive
+ read -r public_key preshared_key endpoint allowed_ips latest_handshake transfer_rx transfer_tx persistent_keepalive
printf '%s\t\t\t"%s": {' "$delim" "$public_key"
delim=$'\n'
+ [[ $preshared_key == "(none)" ]] || { printf '%s\t\t\t\t"presharedKey": "%s"' "$delim" "$preshared_key"; delim=$',\n'; }
[[ $endpoint == "(none)" ]] || { printf '%s\t\t\t\t"endpoint": "%s"' "$delim" "$endpoint"; delim=$',\n'; }
[[ $latest_handshake == "0" ]] || { printf '%s\t\t\t\t"latestHandshake": %u' "$delim" $(( $latest_handshake )); delim=$',\n'; }
[[ $transfer_rx == "0" ]] || { printf '%s\t\t\t\t"transferRx": %u' "$delim" $(( $transfer_rx )); delim=$',\n'; }
fi
if [[ $COMP_CWORD -eq 3 && ${COMP_WORDS[1]} == show && ${COMP_WORDS[2]} != interfaces ]]; then
- COMPREPLY+=( $(compgen -W "public-key private-key preshared-key listen-port peers endpoints allowed-ips fwmark latest-handshakes persistent-keepalive transfer dump" -- "${COMP_WORDS[3]}") )
+ COMPREPLY+=( $(compgen -W "public-key private-key listen-port peers preshared-keys endpoints allowed-ips fwmark latest-handshakes persistent-keepalive transfer dump" -- "${COMP_WORDS[3]}") )
return
fi
[[ ${COMP_WORDS[i]} == listen-port ]] && has_listen_port=1
[[ ${COMP_WORDS[i]} == fwmark ]] && has_fwmark=1
[[ ${COMP_WORDS[i]} == private-key ]] && has_private_key=1
- [[ ${COMP_WORDS[i]} == preshared-key ]] && has_preshared_key=1
[[ ${COMP_WORDS[i]} == peer ]] && { has_peer=$i; break; }
done
if [[ $has_peer -eq 0 ]]; then
[[ $has_listen_port -eq 1 ]] || words+=( listen-port )
[[ $has_fwmark -eq 1 ]] || words+=( fwmark )
[[ $has_private_key -eq 1 ]] || words+=( private-key )
- [[ $has_preshared_key -eq 1 ]] || words+=( preshared-key )
words+=( peer )
COMPREPLY+=( $(compgen -W "${words[*]}" -- "${COMP_WORDS[COMP_CWORD]}") )
elif [[ ${COMP_WORDS[COMP_CWORD-1]} == *-key ]]; then
has_endpoint=0
has_persistent_keepalive=0
has_allowed_ips=0
+ has_preshared_key=0
[[ ${COMP_WORDS[i+2]} == = ]] && ((i+=2)) || ((i++))
continue
fi
[[ ${COMP_WORDS[i]} == endpoint ]] && has_endpoint=1
[[ ${COMP_WORDS[i]} == persistent-keepalive ]] && has_persistent_keepalive=1
[[ ${COMP_WORDS[i]} == allowed-ips ]] && has_allowed_ips=1
+ [[ ${COMP_WORDS[i]} == preshared-key ]] && has_preshared_key=1
[[ ${COMP_WORDS[i]} == remove ]] || ((i++))
done
((COMP_CWORD == j)) || return
if [[ $has_remove -ne 1 ]]; then
+ [[ $has_preshared_key -eq 1 ]] || words+=( preshared-key )
[[ $has_endpoint -eq 1 ]] || words+=( endpoint )
[[ $has_allowed_ips -eq 1 ]] || words+=( allowed-ips )
[[ $has_persistent_keepalive -eq 1 ]] || words+=( persistent-keepalive )
ret = parse_key(ctx->buf.dev->private_key, value);
if (!ret)
memset(ctx->buf.dev->private_key, 0, WG_KEY_LEN);
- } else if (key_match("PresharedKey")) {
- ret = parse_key(ctx->buf.dev->preshared_key, value);
- if (!ret)
- memset(ctx->buf.dev->preshared_key, 0, WG_KEY_LEN);
} else
goto error;
} else if (ctx->is_peer_section) {
ret = parse_ipmasks(&ctx->buf, ctx->peer_offset, value);
else if (key_match("PersistentKeepalive"))
ret = parse_persistent_keepalive(&peer_from_offset(ctx->buf.dev, ctx->peer_offset)->persistent_keepalive_interval, value);
- else
+ else if (key_match("PresharedKey")) {
+ ret = parse_key(peer_from_offset(ctx->buf.dev, ctx->peer_offset)->preshared_key, value);
+ if (!ret)
+ memset(peer_from_offset(ctx->buf.dev, ctx->peer_offset)->preshared_key, 0, WG_KEY_LEN);
+ } else
goto error;
} else
goto error;
fprintf(stderr, "No private key configured\n");
goto err;
}
- if (ctx->buf.dev->flags & WGDEVICE_REPLACE_PEERS && !key_is_valid(ctx->buf.dev->preshared_key))
- ctx->buf.dev->flags |= WGDEVICE_REMOVE_PRESHARED_KEY;
if (ctx->buf.dev->flags & WGDEVICE_REPLACE_PEERS && !ctx->buf.dev->fwmark)
ctx->buf.dev->flags |= WGDEVICE_REMOVE_FWMARK;
goto error;
argv += 2;
argc -= 2;
- } else if (!strcmp(argv[0], "preshared-key") && argc >= 2 && !buf.dev->num_peers) {
- char *line;
- int ret = read_line(&line, argv[1]);
- if (ret == 0) {
- if (!parse_key(buf.dev->preshared_key, line)) {
- free(line);
- goto error;
- }
- free(line);
- } else if (ret == 1)
- buf.dev->flags |= WGDEVICE_REMOVE_PRESHARED_KEY;
- else
- goto error;
- argv += 2;
- argc -= 2;
} else if (!strcmp(argv[0], "peer") && argc >= 2) {
peer_offset = buf.pos;
if (use_space(&buf, sizeof(struct wgpeer)) < 0) {
goto error;
argv += 2;
argc -= 2;
+ } else if (!strcmp(argv[0], "preshared-key") && argc >= 2 && buf.dev->num_peers) {
+ char *line;
+ int ret = read_line(&line, argv[1]);
+ if (ret == 0) {
+ if (!parse_key(peer_from_offset(buf.dev, peer_offset)->preshared_key, line)) {
+ free(line);
+ goto error;
+ }
+ free(line);
+ } else if (ret == 1) {
+ free(line);
+ buf.dev->flags |= WGPEER_REMOVE_PRESHARED_KEY;
+ } else
+ goto error;
+ argv += 2;
+ argc -= 2;
} else {
fprintf(stderr, "Invalid argument: %s\n", argv[0]);
goto error;
int ret = 1;
if (argc < 3) {
- fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
+ fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
return 1;
}
static const char *COMMAND_NAME = NULL;
static void show_usage(void)
{
- fprintf(stderr, "Usage: %s %s { <interface> | all | interfaces } [public-key | private-key | preshared-key | listen-port | fwmark | peers | endpoints | allowed-ips | latest-handshakes | transfer | persistent-keepalive | dump]\n", PROG_NAME, COMMAND_NAME);
+ fprintf(stderr, "Usage: %s %s { <interface> | all | interfaces } [public-key | private-key | listen-port | fwmark | peers | preshared-keys | endpoints | allowed-ips | latest-handshakes | transfer | persistent-keepalive | dump]\n", PROG_NAME, COMMAND_NAME);
}
static void pretty_print(struct wgdevice *device)
terminal_printf(" " TERMINAL_BOLD "public key" TERMINAL_RESET ": %s\n", key(device->public_key));
if (memcmp(device->private_key, zero, WG_KEY_LEN))
terminal_printf(" " TERMINAL_BOLD "private key" TERMINAL_RESET ": %s\n", masked_key(device->private_key));
- if (memcmp(device->preshared_key, zero, WG_KEY_LEN))
- terminal_printf(" " TERMINAL_BOLD "preshared key" TERMINAL_RESET ": %s\n", masked_key(device->preshared_key));
if (device->port)
terminal_printf(" " TERMINAL_BOLD "listening port" TERMINAL_RESET ": %u\n", device->port);
if (device->fwmark)
}
for_each_wgpeer(device, peer, i) {
terminal_printf(TERMINAL_FG_YELLOW TERMINAL_BOLD "peer" TERMINAL_RESET ": " TERMINAL_FG_YELLOW "%s" TERMINAL_RESET "\n", key(peer->public_key));
+ if (memcmp(peer->preshared_key, zero, WG_KEY_LEN))
+ terminal_printf(" " TERMINAL_BOLD "preshared key" TERMINAL_RESET ": %s\n", masked_key(peer->preshared_key));
if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6)
terminal_printf(" " TERMINAL_BOLD "endpoint" TERMINAL_RESET ": %s\n", endpoint(&peer->endpoint.addr));
terminal_printf(" " TERMINAL_BOLD "allowed ips" TERMINAL_RESET ": ");
printf("%s\t", device->interface);
printf("%s\t", key(device->private_key));
printf("%s\t", key(device->public_key));
- printf("%s\t", key(device->preshared_key));
printf("%u\t", device->port);
if (device->fwmark)
printf("0x%x\n", device->fwmark);
if (with_interface)
printf("%s\t", device->interface);
printf("%s\t", key(peer->public_key));
+ printf("%s\t", key(peer->preshared_key));
if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6)
printf("%s\t", endpoint(&peer->endpoint.addr));
else
if (with_interface)
printf("%s\t", device->interface);
printf("%s\n", key(device->private_key));
- } else if (!strcmp(param, "preshared-key")) {
- if (with_interface)
- printf("%s\t", device->interface);
- printf("%s\n", key(device->preshared_key));
} else if (!strcmp(param, "listen-port")) {
if (with_interface)
printf("%s\t", device->interface);
else
printf("%s\toff\n", key(peer->public_key));
}
+ } else if (!strcmp(param, "preshared-keys")) {
+ for_each_wgpeer(device, peer, i) {
+ if (with_interface)
+ printf("%s\t", device->interface);
+ printf("%s\t", key(peer->public_key));
+ printf("%s\n", key(peer->preshared_key));
+ }
} else if (!strcmp(param, "peers")) {
for_each_wgpeer(device, peer, i) {
if (with_interface)
key_to_base64(base64, device->private_key);
printf("PrivateKey = %s\n", base64);
}
- if (memcmp(device->preshared_key, zero, WG_KEY_LEN)) {
- key_to_base64(base64, device->preshared_key);
- printf("PresharedKey = %s\n", base64);
- }
printf("\n");
for_each_wgpeer(device, peer, i) {
key_to_base64(base64, peer->public_key);
printf("[Peer]\nPublicKey = %s\n", base64);
+ if (memcmp(peer->preshared_key, zero, WG_KEY_LEN)) {
+ key_to_base64(base64, peer->preshared_key);
+ printf("PresharedKey = %s\n", base64);
+ }
if (peer->num_ipmasks)
printf("AllowedIPs = ");
for_each_wgipmask(peer, ipmask, j) {
.SH COMMANDS
.TP
-\fBshow\fP { \fI<interface>\fP | \fIall\fP | \fIinterfaces\fP } [\fIpublic-key\fP | \fIprivate-key\fP | \fIpreshared-key\fP | \fIlisten-port\fP | \fIfwmark\fP | \fIpeers\fP | \fIendpoints\fP | \fIallowed-ips\fP | \fIlatest-handshakes\fP | \fIpersistent-keepalive\fP | \fItransfer\fP | \fIdump\fP]
+\fBshow\fP { \fI<interface>\fP | \fIall\fP | \fIinterfaces\fP } [\fIpublic-key\fP | \fIprivate-key\fP | \fIlisten-port\fP | \fIfwmark\fP | \fIpeers\fP | \fIpreshared-keys\fP | \fIendpoints\fP | \fIallowed-ips\fP | \fIlatest-handshakes\fP | \fIpersistent-keepalive\fP | \fItransfer\fP | \fIdump\fP]
Shows current WireGuard configuration of specified \fI<interface>\fP.
If no \fI<interface>\fP is specified, \fI<interface>\fP defaults to \fIall\fP.
If \fIinterfaces\fP is specified, prints a list of all WireGuard interfaces,
newlines and tabs, meant to be used in scripts. For this script-friendly display,
if \fIall\fP is specified, then the first field for all categories of information
is the interface name. If \fPdump\fP is specified, then several lines are printed;
-the first contains in order separated by tab: private-key, public-key, preshared-key,
-listen-port, fwmark. Subsequent lines are printed for each peer and contain in order
-separated by tab: public-key, endpoint, allowed-ips, latest-handshake, transfer-rx,
-transfer-tx, persistent-keepalive.
+the first contains in order separated by tab: private-key, public-key, listen-port,
+fwmark. Subsequent lines are printed for each peer and contain in order separated
+by tab: public-key, preshared-key, endpoint, allowed-ips, latest-handshake,
+transfer-rx, transfer-tx, persistent-keepalive.
.TP
\fBshowconf\fP \fI<interface>\fP
Shows the current configuration of \fI<interface>\fP in the format described
by \fICONFIGURATION FILE FORMAT\fP below.
.TP
-\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]...
+\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]...
Sets configuration values for the specified \fI<interface>\fP. Multiple
\fIpeer\fPs may be specified, and if the \fIremove\fP argument is given
for a peer, that peer is removed, not configured. If \fIlisten-port\fP
.IP \(bu
PrivateKey \(em a base64 private key generated by \fIwg genkey\fP. Required.
.IP \(bu
-PresharedKey \(em a base64 preshared key generated by \fIwg genpsk\fP. Optional,
-and may be omitted. This option adds an additional layer of symmetric-key
-cryptography to be mixed into the already existing public-key cryptography,
-for post-quantum resistance.
-.IP \(bu
ListenPort \(em a 16-bit port for listening. Optional; if not specified, chosen
randomly.
.IP \(bu
private key, and usually transmitted out of band to the author of the
configuration file. Required.
.IP \(bu
+PresharedKey \(em a base64 preshared key generated by \fIwg genpsk\fP. Optional,
+and may be omitted. This option adds an additional layer of symmetric-key
+cryptography to be mixed into the already existing public-key cryptography,
+for post-quantum resistance.
+.IP \(bu
AllowedIPs \(em a comma-separated list of ip (v4 or v6) addresses with
CIDR masks from which this peer is allowed to send incoming traffic and
to which outgoing traffic for this peer is directed. The catch-all