@@ -24,9 +24,6 @@
#include "proto.h"
#include "skb.h"
-#define OVPN_AUTH_TAG_SIZE 16
-#define OVPN_AAD_SIZE (OVPN_OPCODE_SIZE + OVPN_NONCE_WIRE_SIZE)
-
#define ALG_NAME_AES "gcm(aes)"
#define ALG_NAME_CHACHAPOLY "rfc7539(chacha20,poly1305)"
#define OVPN_AEAD_DECRYPT_FAILURE_NOTIFY BIT_ULL(35)
@@ -51,9 +48,7 @@ bool ovpn_aead_decrypt_failure_record(struct ovpn_crypto_key_slot *ks)
static int ovpn_aead_encap_overhead(const struct ovpn_crypto_key_slot *ks)
{
- return OVPN_OPCODE_SIZE + /* OP header size */
- sizeof(u32) + /* Packet ID */
- crypto_aead_authsize(ks->encrypt); /* Auth Tag */
+ return OVPN_AEAD_DIRECT_AAD_SIZE + crypto_aead_authsize(ks->encrypt);
}
/**
@@ -163,6 +158,7 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
struct sk_buff *trailer;
struct scatterlist *sg;
int nfrags, ret;
+ u64 aead_blocks;
u32 pktid, op;
void *tmp;
u8 *iv;
@@ -205,7 +201,7 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
sg = ovpn_aead_crypto_req_sg(ks->encrypt, req);
/* sg table:
- * 0: op, wire nonce (AD, len=OVPN_OP_SIZE_V2+OVPN_NONCE_WIRE_SIZE),
+ * 0: op, wire nonce (AD, len=OVPN_AEAD_DIRECT_AAD_SIZE),
* 1, 2, 3, ..., n: payload,
* n+1: auth_tag (len=tag_size)
*/
@@ -226,12 +222,11 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
/* obtain packet ID, which is used both as a first
* 4 bytes of nonce and last 4 bytes of associated data.
*/
+ aead_blocks = ovpn_aead_limit_blocks(ks->cipher_alg,
+ OVPN_AEAD_DIRECT_AAD_SIZE,
+ plaintext_len);
ret = ovpn_pktid_xmit_next(&ks->pid_xmit, &ks->usage_xmit,
- &ks->usage_limit,
- ovpn_aead_limit_blocks(ks->cipher_alg,
- OVPN_AAD_SIZE,
- plaintext_len),
- &pktid);
+ &ks->usage_limit, aead_blocks, &pktid);
if (unlikely(ret < 0))
return ret;
if (unlikely(ret > 0))
@@ -253,14 +248,14 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
*((__force __be32 *)skb->data) = htonl(op);
/* AEAD Additional data */
- sg_set_buf(sg, skb->data, OVPN_AAD_SIZE);
+ sg_set_buf(sg, skb->data, OVPN_AEAD_DIRECT_AAD_SIZE);
/* setup async crypto operation */
aead_request_set_tfm(req, ks->encrypt);
aead_request_set_callback(req, 0, ovpn_encrypt_post, skb);
aead_request_set_crypt(req, sg, sg,
skb->len - ovpn_aead_encap_overhead(ks), iv);
- aead_request_set_ad(req, OVPN_AAD_SIZE);
+ aead_request_set_ad(req, OVPN_AEAD_DIRECT_AAD_SIZE);
/* encrypt it */
return crypto_aead_encrypt(req);
@@ -278,7 +273,7 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
void *tmp;
u8 *iv;
- payload_offset = OVPN_AAD_SIZE + tag_size;
+ payload_offset = ovpn_aead_direct_payload_offset(tag_size);
payload_len = skb->len - payload_offset;
ovpn_skb_cb(skb)->payload_offset = payload_offset;
@@ -320,14 +315,14 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
sg = ovpn_aead_crypto_req_sg(ks->decrypt, req);
/* sg table:
- * 0: op, wire nonce (AD, len=OVPN_OPCODE_SIZE+OVPN_NONCE_WIRE_SIZE),
+ * 0: op, wire nonce (AD, len=OVPN_AEAD_DIRECT_AAD_SIZE),
* 1, 2, 3, ..., n: payload,
* n+1: auth_tag (len=tag_size)
*/
sg_init_table(sg, nfrags + 2);
/* packet op is head of additional data */
- sg_set_buf(sg, skb->data, OVPN_AAD_SIZE);
+ sg_set_buf(sg, skb->data, OVPN_AEAD_DIRECT_AAD_SIZE);
/* build scatterlist to decrypt packet payload */
ret = skb_to_sgvec_nomark(skb, sg + 1, payload_offset, payload_len);
@@ -338,10 +333,11 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
}
/* append auth_tag onto scatterlist */
- sg_set_buf(sg + ret + 1, skb->data + OVPN_AAD_SIZE, tag_size);
+ sg_set_buf(sg + ret + 1, skb->data + OVPN_AEAD_DIRECT_TAG_OFFSET,
+ tag_size);
/* copy nonce into IV buffer */
- memcpy(iv, skb->data + OVPN_OPCODE_SIZE, OVPN_NONCE_WIRE_SIZE);
+ memcpy(iv, ovpn_aead_direct_wire_nonce(skb), OVPN_NONCE_WIRE_SIZE);
memcpy(iv + OVPN_NONCE_WIRE_SIZE, ks->nonce_tail_recv,
OVPN_NONCE_TAIL_SIZE);
@@ -350,7 +346,7 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks,
aead_request_set_callback(req, 0, ovpn_decrypt_post, skb);
aead_request_set_crypt(req, sg, sg, payload_len + tag_size, iv);
- aead_request_set_ad(req, OVPN_AAD_SIZE);
+ aead_request_set_ad(req, OVPN_AEAD_DIRECT_AAD_SIZE);
/* decrypt it */
return crypto_aead_decrypt(req);
@@ -380,7 +376,7 @@ static struct crypto_aead *ovpn_aead_init(const char *title,
goto error;
}
- ret = crypto_aead_setauthsize(aead, OVPN_AUTH_TAG_SIZE);
+ ret = crypto_aead_setauthsize(aead, OVPN_AEAD_TAG_SIZE);
if (ret) {
pr_err("%s crypto_aead_setauthsize failed, err=%d\n", title,
ret);
@@ -114,7 +114,7 @@ void ovpn_decrypt_post(void *data, int ret)
struct ovpn_peer *peer;
u64 aead_blocks;
__be16 proto;
- __be32 *pid;
+ u32 pktid;
/* crypto is happening asynchronously. this function will be called
* again later by the crypto callback with a proper return code
@@ -138,9 +138,8 @@ void ovpn_decrypt_post(void *data, int ret)
if (unlikely(ret < 0))
goto drop;
- /* PID sits after the op */
- pid = (__force __be32 *)(skb->data + OVPN_OPCODE_SIZE);
- ret = ovpn_pktid_recv(&ks->pid_recv, ntohl(*pid), 0);
+ pktid = ovpn_aead_direct_pktid(skb);
+ ret = ovpn_pktid_recv(&ks->pid_recv, pktid, 0);
if (unlikely(ret < 0)) {
net_err_ratelimited("%s: PKT ID RX error for peer %u: %d\n",
netdev_name(peer->ovpn->dev), peer->id,
@@ -149,8 +148,7 @@ void ovpn_decrypt_post(void *data, int ret)
}
aead_blocks = ovpn_aead_limit_blocks(ks->cipher_alg,
- OVPN_OPCODE_SIZE +
- OVPN_NONCE_WIRE_SIZE,
+ OVPN_AEAD_DIRECT_AAD_SIZE,
skb->len - payload_offset);
if (unlikely(ovpn_pktid_recv_update_aead(&ks->pid_recv,
&ks->usage_recv,
@@ -10,10 +10,10 @@
#ifndef _NET_OVPN_OVPN_H_
#define _NET_OVPN_OVPN_H_
-/* DATA_V2 header size with AEAD encryption */
-#define OVPN_HEAD_ROOM (OVPN_OPCODE_SIZE + OVPN_NONCE_WIRE_SIZE + \
- 16 /* AEAD TAG length */ + \
- max(sizeof(struct udphdr), sizeof(struct tcphdr)) +\
+/* headroom needed by directly installed AEAD keys */
+#define OVPN_HEAD_ROOM (OVPN_AEAD_DIRECT_AAD_SIZE + \
+ OVPN_AEAD_TAG_SIZE + \
+ max(sizeof(struct udphdr), sizeof(struct tcphdr)) + \
max(sizeof(struct ipv6hdr), sizeof(struct iphdr)))
/* max padding required by encryption */
@@ -47,8 +47,38 @@
#define OVPN_DATA_V1 6 /* data channel v1 packet */
#define OVPN_DATA_V2 9 /* data channel v2 packet */
+/* direct-key AEAD packet layout */
+#define OVPN_AEAD_TAG_SIZE 16
+#define OVPN_AEAD_DIRECT_OP_OFFSET 0
+#define OVPN_AEAD_DIRECT_PKTID_OFFSET (OVPN_AEAD_DIRECT_OP_OFFSET + \
+ OVPN_OPCODE_SIZE)
+#define OVPN_AEAD_DIRECT_TAG_OFFSET (OVPN_AEAD_DIRECT_PKTID_OFFSET + \
+ OVPN_NONCE_WIRE_SIZE)
+#define OVPN_AEAD_DIRECT_AAD_SIZE OVPN_AEAD_DIRECT_TAG_OFFSET
+
#define OVPN_PEER_ID_UNDEF 0x00FFFFFF
+static inline unsigned int
+ovpn_aead_direct_payload_offset(unsigned int tag_size)
+{
+ return OVPN_AEAD_DIRECT_TAG_OFFSET + tag_size;
+}
+
+static inline u32 ovpn_aead_direct_pktid(const struct sk_buff *skb)
+{
+ const __be32 *pktid;
+
+ pktid = (__force const __be32 *)(skb->data +
+ OVPN_AEAD_DIRECT_PKTID_OFFSET);
+
+ return be32_to_cpu(*pktid);
+}
+
+static inline u8 *ovpn_aead_direct_wire_nonce(struct sk_buff *skb)
+{
+ return skb->data + OVPN_AEAD_DIRECT_PKTID_OFFSET;
+}
+
/**
* ovpn_opcode_from_skb - extract OP code from skb at specified offset
* @skb: the packet to extract the OP code from