Permalink
Browse files

Merge #1055 branch 'snabbco/max-next' into next

  • Loading branch information...
2 parents bb302a0 + 3e0642f commit c47074dc7babbaa2ea25f093900cbce42d4c5829 @lukego lukego committed Nov 3, 2016
@@ -2,17 +2,13 @@
## AES128gcm (apps.ipsec.esp)
-The `AES128gcm` implements an ESP transport tunnel using the AES-GCM-128
+The `AES128gcm` implements ESP in transport mode using the AES-GCM-128
cipher. It encrypts packets received on its `decapsulated` port and transmits
them on its `encapsulated` port, and vice-versa. Packets arriving on the
`decapsulated` port must have an IPv6 header, and packets arriving on the
`encapsulated` port must have an IPv6 header followed by an ESP header,
otherwise they will be discarded.
-References:
-
- - `lib.ipsec.esp`
-
DIAGRAM: AES128gcm
+-----------+
encapsulated | |
@@ -26,19 +22,60 @@ References:
<-------|---/ /------->
\-----/ decapsulated
+References:
+
+ - `lib.ipsec.esp`
+
### Configuration
The `AES128gcm` app accepts a table as its configuration argument. The
following keys are defined:
— Key **spi**
-*Required*. Security Parameter Index. A 32 bit integer.
+*Required*. A 32 bit integer denoting the “Security Parameters Index” as
+specified in RFC 4303.
+
+— Key **transmit_key**
+
+*Required*. Hexadecimal string of 32 digits (two digits for each byte) that
+denotes a 128-bit AES key as specified in RFC 4106 used for the encryption of
+outgoing packets.
+
+— Key **transmit_salt**
+
+*Required*. Hexadecimal string of eight digits (two digits for each byte) that
+denotes four bytes of salt as specified in RFC 4106 used for the encryption of
+outgoing packets.
+
+— Key **receive_key**
+
+*Required*. Hexadecimal string of 32 digits (two digits for each byte) that
+denotes a 128-bit AES key as specified in RFC 4106 used for the decryption of
+incoming packets.
+
+— Key **receive_salt**
+
+*Required*. Hexadecimal string of eight digits (two digits for each byte) that
+denotes four bytes of salt as specified in RFC 4106 used for the decryption of
+incoming packets.
+
+— Key **receive_window**
+
+*Optional*. Minimum width of the window in which out of order packets are
+accepted as specified in RFC 4303. The default is 128.
+
+— Key **resync_threshold**
+
+*Optional*. Number of consecutive packets allowed to fail decapsulation before
+attempting “Re-synchronization” as specified in RFC 4303. The default is 1024.
-— Key **key**
+— Key **resync_attempts**
-*Required*. 20 bytes in form of a hex encoded string.
+*Optional*. Number of attempts to re-synchronize a packet that triggered
+“Re-synchronization” as specified in RFC 4303. The default is 8.
-— Key **replay_window**
+— Key **auditing**
-*Optional*. Size of the “Anti-Replay Window”. Defaults to 128.
+*Optional.* A boolean value indicating whether to enable or disable “Auditing”
+as specified in RFC 4303. The default is `nil` (no auditing).
@@ -10,7 +10,15 @@ local C = require("ffi").C
AES128gcm = {
config = {
- spi = {required=true}, key = {required=true}, window_size = {}
+ spi = {required=true},
+ transmit_key = {required=true},
+ transmit_salt = {required=true},
+ receive_key = {required=true},
+ receive_salt = {required=true},
+ receive_window = {},
+ resync_threshold = {},
+ resync_attempts = {},
+ auditing = {}
},
shm = {
txerrors = {counter}, rxerrors = {counter}
@@ -19,17 +27,22 @@ AES128gcm = {
function AES128gcm:new (conf)
local self = {}
+ assert(conf.transmit_salt ~= conf.receive_salt,
+ "Refusing to operate with transmit_salt == receive_salt")
self.encrypt = esp.esp_v6_encrypt:new{
mode = "aes-128-gcm",
spi = conf.spi,
- keymat = conf.key:sub(1, 32),
- salt = conf.key:sub(33, 40)}
+ key = conf.transmit_key,
+ salt = conf.transmit_salt}
self.decrypt = esp.esp_v6_decrypt:new{
mode = "aes-128-gcm",
spi = conf.spi,
- keymat = conf.key:sub(1, 32),
- salt = conf.key:sub(33, 40),
- window_size = conf.replay_window}
+ key = conf.receive_key,
+ salt = conf.receive_salt,
+ window_size = conf.receive_window,
+ resync_threshold = conf.resync_threshold,
+ resync_attempts = conf.resync_attempts,
+ auditing = conf.auditing}
return setmetatable(self, {__index = AES128gcm})
end
View
@@ -62,6 +62,8 @@ $(cat $mdroot/apps/vlan/README.md)
$(cat $mdroot/apps/bridge/README.md)
+$(cat $mdroot/apps/ipsec/README.md)
+
$(cat $mdroot/apps/test/README.md)
# Libraries
@@ -82,7 +84,7 @@ $(cat $mdroot/lib/protocol/README.md)
## IPsec
-$(cat ../lib/ipsec/README.md)
+$(cat $mdroot/lib/ipsec/README.md)
## Snabb NFV
@@ -13,12 +13,25 @@ UDP, L2TPv3) and also encrypts the contents of the inner protocol
header. The decrypt class does the reverse: it decrypts the inner
protocol header and removes the ESP protocol header.
-Anti-replay protection as well as recovery from synchronization loss due to
-excessive packet loss are *not* implemented.
+ DIAGRAM: ESP-Transport
+ BEFORE ENCAPSULATION
+ +-----------+-------------+------------+
+ |orig Ether‑| orig IP Hdr | |
+ |net Hdr |(any options)| Payload |
+ +-----------+-------------+------------+
+
+ AFTER ENCAPSULATION
+ +-----------+-------------+-----+------------+---------+----+
+ |orig Ether‑| orig IP Hd | ESP | | ESP | ESP|
+ |net Hdr |(any options)| Hdr | Payload | Trailer | ICV|
+ +-----------+-------------+-----+------------+---------+----+
+ <-----encryption----->
+ <---------integrity-------->
References:
- [IPsec Wikipedia page](https://en.wikipedia.org/wiki/IPsec).
+- [RFC 4303](https://tools.ietf.org/html/rfc4303) on IPsec ESP.
- [RFC 4106](https://tools.ietf.org/html/rfc4106) on using AES-GCM with IPsec ESP.
- [LISP Data-Plane Confidentiality](https://tools.ietf.org/html/draft-ietf-lisp-crypto-02) example of a software layer above these apps that includes key exchange.
@@ -31,19 +44,21 @@ be a table with the following keys:
* `mode` - Encryption mode (string). The only accepted value is the
string `"aes-128-gcm"`.
-* `keymat` - Hex string containing 16 bytes of key material as specified
- in RFC 4106.
-* `salt` - Hex string containing four bytes of salt as specified in
- RFC 4106.
-* `spi` - “Security Parameter Index” as specified in RFC 4303.
-* `window_size` - *Optional*. Width of the window in which out of order packets
- are accepted. The default is 128. (`esp_v6_decrypt` only.)
+* `spi` - A 32 bit integer denoting the “Security Parameters Index” as
+ specified in RFC 4303.
+* `key` - Hexadecimal string of 32 digits (two digits for each byte) that
+ denotes a 128-bit AES key as specified in RFC 4106.
+* `salt` - Hexadecimal string of eight digits (two digits for each byte) that
+ denotes four bytes of salt as specified in RFC 4106.
+* `window_size` - *Optional*. Minimum width of the window in which out of order
+ packets are accepted as specified in RFC 4303. The default is 128.
+ (`esp_v6_decrypt` only.)
* `resync_threshold` - *Optional*. Number of consecutive packets allowed to
- fail decapsulation before attempting re-synchronization. The default is
- 10,000. (`esp_v6_decrypt` only.)
+ fail decapsulation before attempting “Re-synchronization” as specified in
+ RFC 4303. The default is 1024. (`esp_v6_decrypt` only.)
* `resync_attempts` - *Optional*. Number of attempts to re-synchronize
- a packet that triggered re-synchronization. The default is 10.
- (`esp_v6_decrypt` only.)
+ a packet that triggered “Re-synchronization” as specified in RFC 4303. The
+ default is 8. (`esp_v6_decrypt` only.)
* `auditing` - *Optional.* A boolean value indicating whether to enable or
disable “Auditing” as specified in RFC 4303. The default is `nil` (no
auditing). (`esp_v6_decrypt` only.)
@@ -68,21 +68,21 @@ end
local function u8_ptr (ptr) return ffi.cast("uint8_t *", ptr) end
-- Encrypt a single 128-bit block with the basic AES block cipher.
-local function aes_128_block (block, keymat)
+local function aes_128_block (block, key)
local gcm_data = ffi.new("gcm_data __attribute__((aligned(16)))")
- ASM.aes_keyexp_128_enc_avx(keymat, gcm_data)
+ ASM.aes_keyexp_128_enc_avx(key, gcm_data)
ASM.aesni_encrypt_single_block(gcm_data, block)
end
local aes_128_gcm = {}
-function aes_128_gcm:new (spi, keymat, salt)
+function aes_128_gcm:new (spi, key, salt)
assert(spi, "Need SPI.")
- assert(keymat and #keymat == 32, "Need 16 bytes of key material.")
+ assert(key and #key == 32, "Need 16 bytes of key material.")
assert(salt and #salt == 8, "Need 4 bytes of salt.")
local o = {}
- o.keymat = ffi.new("uint8_t[16]")
- ffi.copy(o.keymat, lib.hexundump(keymat, 16), 16)
+ o.key = ffi.new("uint8_t[16]")
+ ffi.copy(o.key, lib.hexundump(key, 16), 16)
o.IV_SIZE = 8
o.iv = iv:new(lib.hexundump(salt, 4))
o.AUTH_SIZE = 16
@@ -91,9 +91,9 @@ function aes_128_gcm:new (spi, keymat, salt)
o.aad = aad:new(spi)
-- Compute subkey (H)
o.hash_subkey = ffi.new("uint8_t[?] __attribute__((aligned(16)))", 16)
- aes_128_block(o.hash_subkey, o.keymat)
+ aes_128_block(o.hash_subkey, o.key)
o.gcm_data = ffi.new("gcm_data __attribute__((aligned(16)))")
- ASM.aes_keyexp_128_enc_avx(o.keymat, o.gcm_data)
+ ASM.aes_keyexp_128_enc_avx(o.key, o.gcm_data)
ASM.aesni_gcm_precomp_avx_gen4(o.gcm_data, o.hash_subkey)
return setmetatable(o, {__index=aes_128_gcm})
end
@@ -42,7 +42,7 @@ local ESP_TAIL_SIZE = esp_tail:sizeof()
function esp_v6_new (conf)
assert(conf.mode == "aes-128-gcm", "Only supports aes-128-gcm.")
assert(conf.spi, "Need SPI.")
- local gcm = aes_128_gcm:new(conf.spi, conf.keymat, conf.salt)
+ local gcm = aes_128_gcm:new(conf.spi, conf.key, conf.salt)
local o = {}
o.ESP_OVERHEAD = ESP_SIZE + ESP_TAIL_SIZE + gcm.IV_SIZE + gcm.AUTH_SIZE
o.aes_128_gcm = gcm
@@ -115,9 +115,9 @@ function esp_v6_decrypt:new (conf)
o.CTEXT_OFFSET = ESP_SIZE + gcm.IV_SIZE
o.PLAIN_OVERHEAD = PAYLOAD_OFFSET + ESP_SIZE + gcm.IV_SIZE + gcm.AUTH_SIZE
o.window_size = conf.window_size or 128
+ o.window_size = o.window_size + padding(8, o.window_size)
o.resync_threshold = conf.resync_threshold or 1024
o.resync_attempts = conf.resync_attempts or 8
- assert(o.window_size % 8 == 0, "window_size must be a multiple of 8.")
o.window = ffi.new(window_t, o.window_size / 8)
o.decap_fail = 0
o.auditing = conf.auditing
@@ -214,7 +214,7 @@ function selftest ()
local ipv6 = require("lib.protocol.ipv6")
local conf = { spi = 0x0,
mode = "aes-128-gcm",
- keymat = "00112233445566778899AABBCCDDEEFF",
+ key = "00112233445566778899AABBCCDDEEFF",
salt = "00112233",
resync_threshold = 16,
resync_attempts = 8}
@@ -148,6 +148,7 @@ function ipv4:protocol (protocol)
end
function ipv4:checksum ()
+ self:header().checksum = 0
self:header().checksum = htons(ipsum(ffi.cast("uint8_t *", self:header()),
self:sizeof(), 0))
return ntohs(self:header().checksum)
@@ -206,7 +207,7 @@ local function test_ipv4_checksum ()
local p = packet.from_string(lib.hexundump([[
52:54:00:02:02:02 52:54:00:01:01:01 08 00 45 00
- 00 34 59 1a 40 00 40 06 00 00 c0 a8 14 a9 6b 15
+ 00 34 59 1a 40 00 40 06 b0 8e c0 a8 14 a9 6b 15
f0 b4 de 0b 01 bb e7 db 57 bc 91 cd 18 32 80 10
05 9f 00 00 00 00 01 01 08 0a 06 0c 5c bd fa 4a
e1 65
@@ -352,7 +352,7 @@ function esp (npackets, packet_size, mode, profile)
local plain = d:packet()
local conf = { spi = 0x0,
mode = "aes-128-gcm",
- keymat = "00112233445566778899AABBCCDDEEFF",
+ key = "00112233445566778899AABBCCDDEEFF",
salt = "00112233"}
local enc, dec = esp.esp_v6_encrypt:new(conf), esp.esp_v6_decrypt:new(conf)
@@ -51,8 +51,8 @@ port := { port_id = <id>, -- A unique string
egress_filter = <filter>, -- ..
tunnel = <tunnel-conf>,
crypto = <crypto-conf>,
- rx_police_gbps = <n>, -- Allowed input rate in Gbps
- tx_police_gbps = <n> } -- Allowed output rate in Gbps
+ rx_police = <n>, -- Allowed input rate in Gbps
+ tx_police = <n> } -- Allowed output rate in Gbps
```
The `tunnel` section deviates a little from `SimpleKeyedTunnel`'s
@@ -69,13 +69,16 @@ tunnel := { type = "L2TPv3", -- The only type (for now)
```
The `crypto` section allows configuration of traffic encryption based on
-`apps.esp`:
+`apps.ipsec.esp`:
```
crypto := { type = "esp-aes-128-gcm", -- The only type (for now)
- spi = <spi>, -- Security Parameter Index
- key = <key>, -- 20 bytes as a hex encoded string
- replay_window = <n> } -- Replay window
+ spi = <spi>, -- As for AES128gcm
+ transmit_key = <key>,
+ transmit_salt = <salt>,
+ receive_key = <key>,
+ receive_salt = <salt>,
+ auditing = <boolean> }
```
@@ -60,13 +60,13 @@ function fuzz_connective_ports (spec)
if spec.tunnel then
ports[1].tunnel, ports[2].tunnel = fuzz_tunnel()
end
- if spec.rx_police_gbps then
- ports[1].rx_police_gbps = random_gbps(spec.rx_police_gbps)
- ports[2].rx_police_gbps = random_gbps(spec.rx_police_gbps)
+ if spec.rx_police then
+ ports[1].rx_police = random_gbps(spec.rx_police)
+ ports[2].rx_police = random_gbps(spec.rx_police)
end
- if spec.tx_police_gbps then
- ports[1].tx_police_gbps = random_gbps(spec.tx_police_gbps)
- ports[2].tx_police_gbps = random_gbps(spec.tx_police_gbps)
+ if spec.tx_police then
+ ports[1].tx_police = random_gbps(spec.tx_police)
+ ports[2].tx_police = random_gbps(spec.tx_police)
end
return ports
end
@@ -107,8 +107,8 @@ function create_config (input_dir, output_dir, hostname)
ingress_filter = filter(port, secbindings, secrules, 'ingress'),
egress_filter = filter(port, secbindings, secrules, 'egress'),
stateful_filter = (profile.packetfilter ~= 'stateless'),
- rx_police_gbps = profile.rx_police_gbps,
- tx_police_gbps = profile.tx_police_gbps,
+ rx_police = profile.rx_police_gbps,
+ tx_police = profile.tx_police_gbps,
tunnel = tunnel(port, vif_details, profile) })
end
end
Oops, something went wrong.

0 comments on commit c47074d

Please sign in to comment.