summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Pomykalov <gleb@lancastr.com>2019-02-18 14:36:46 +0300
committerGleb Pomykalov <gleb@lancastr.com>2019-03-12 13:48:45 +0300
commit6968cb4ab02ec0250cf9859b6d85b04a36dc1ed2 (patch)
tree9a3c6b2d99629fad8f01400b5e450da28d63c995
parent2d0d3609a47c8a684dfc094f81164ca5da1e38d7 (diff)
downloadnix-6968cb4ab02ec0250cf9859b6d85b04a36dc1ed2.zip
Support AF_ALG
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/sys/socket/addr.rs80
-rw-r--r--src/sys/socket/mod.rs111
-rw-r--r--src/sys/socket/sockopt.rs49
-rw-r--r--test/sys/test_socket.rs149
5 files changed, 381 insertions, 11 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81f94c24..7bb653e7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,9 +7,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Add IP_RECVIF & IP_RECVDSTADDR. Enable IP_PKTINFO and IP6_PKTINFO on netbsd/openbsd.
([#1002](https://github.com/nix-rust/nix/pull/1002))
-
- Added `inotify_init1`, `inotify_add_watch` and `inotify_rm_watch` wrappers for
Android and Linux. ([#1016](https://github.com/nix-rust/nix/pull/1016))
+- Add `ALG_SET_IV`, `ALG_SET_OP` and `ALG_SET_AEAD_ASSOCLEN` control messages and `AF_ALG`
+ socket types on Linux and Android ([#1031](https://github.com/nix-rust/nix/pull/1031))
### Changed
- `PollFd` event flags renamed to `PollFlags` ([#1024](https://github.com/nix-rust/nix/pull/1024/))
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index db62b001..13459e9b 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -8,6 +8,8 @@ use std::path::Path;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(target_os = "android", target_os = "linux"))]
use ::sys::socket::addr::netlink::NetlinkAddr;
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use ::sys::socket::addr::alg::AlgAddr;
#[cfg(any(target_os = "ios", target_os = "macos"))]
use std::os::unix::io::RawFd;
#[cfg(any(target_os = "ios", target_os = "macos"))]
@@ -740,6 +742,8 @@ pub enum SockAddr {
Unix(UnixAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink(NetlinkAddr),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Alg(AlgAddr),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SysControl(SysControlAddr),
/// Datalink address (MAC)
@@ -768,6 +772,11 @@ impl SockAddr {
SockAddr::Netlink(NetlinkAddr::new(pid, groups))
}
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
+ SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
+ }
+
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
@@ -780,6 +789,8 @@ impl SockAddr {
SockAddr::Unix(..) => AddressFamily::Unix,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(..) => AddressFamily::Netlink,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Alg(..) => AddressFamily::Alg,
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(..) => AddressFamily::System,
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -856,6 +867,8 @@ impl SockAddr {
SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -910,6 +923,8 @@ impl hash::Hash for SockAddr {
SockAddr::Unix(ref a) => a.hash(s),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(ref a) => a.hash(s),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Alg(ref a) => a.hash(s),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(ref a) => a.hash(s),
#[cfg(any(target_os = "android",
@@ -938,6 +953,8 @@ impl fmt::Display for SockAddr {
SockAddr::Unix(ref unix) => unix.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(ref nl) => nl.fmt(f),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Alg(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(ref sc) => sc.fmt(f),
#[cfg(any(target_os = "android",
@@ -1014,6 +1031,69 @@ pub mod netlink {
}
}
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub mod alg {
+ use libc::{AF_ALG, sockaddr_alg, c_char};
+ use std::{fmt, mem, str};
+ use std::hash::{Hash, Hasher};
+ use std::ffi::CStr;
+
+ #[derive(Copy, Clone)]
+ pub struct AlgAddr(pub sockaddr_alg);
+
+ // , PartialEq, Eq, Debug, Hash
+ impl PartialEq for AlgAddr {
+ fn eq(&self, other: &Self) -> bool {
+ let (inner, other) = (self.0, other.0);
+ (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]) ==
+ (other.salg_family, &other.salg_type[..], other.salg_feat, other.salg_mask, &other.salg_name[..])
+ }
+ }
+
+ impl Eq for AlgAddr {}
+
+ impl Hash for AlgAddr {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ let inner = self.0;
+ (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]).hash(s);
+ }
+ }
+
+ impl AlgAddr {
+ pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr {
+ let mut addr: sockaddr_alg = unsafe { mem::zeroed() };
+ addr.salg_family = AF_ALG as u16;
+ addr.salg_type[..alg_type.len()].copy_from_slice(alg_type.to_string().as_bytes());
+ addr.salg_name[..alg_name.len()].copy_from_slice(alg_name.to_string().as_bytes());
+
+ AlgAddr(addr)
+ }
+
+
+ pub fn alg_type(&self) -> &CStr {
+ unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) }
+ }
+
+ pub fn alg_name(&self) -> &CStr {
+ unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) }
+ }
+ }
+
+ impl fmt::Display for AlgAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "type: {} alg: {}",
+ self.alg_name().to_string_lossy(),
+ self.alg_type().to_string_lossy())
+ }
+ }
+
+ impl fmt::Debug for AlgAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+}
+
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub mod sys_control {
use ::sys::socket::addr::AddressFamily;
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 80009917..5a054b4b 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -31,6 +31,8 @@ pub use self::addr::{
};
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use ::sys::socket::addr::netlink::NetlinkAddr;
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use sys::socket::addr::alg::AlgAddr;
pub use libc::{
cmsghdr,
@@ -700,6 +702,37 @@ pub enum ControlMessage<'a> {
// and put that in here instead of a raw ucred.
#[cfg(any(target_os = "android", target_os = "linux"))]
ScmCredentials(&'a libc::ucred),
+
+ /// Set IV for `AF_ALG` crypto API.
+ ///
+ /// For further information, please refer to the
+ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ ))]
+ AlgSetIv(&'a [u8]),
+ /// Set crypto operation for `AF_ALG` crypto API. It may be one of
+ /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
+ ///
+ /// For further information, please refer to the
+ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ ))]
+ AlgSetOp(&'a libc::c_int),
+ /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
+ /// for `AF_ALG` crypto API.
+ ///
+ /// For further information, please refer to the
+ /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ ))]
+ AlgSetAeadAssoclen(&'a u32),
+
}
// An opaque structure used to prevent cmsghdr from being a public type
@@ -729,8 +762,8 @@ impl<'a> ControlMessage<'a> {
}
/// Return a reference to the payload data as a byte pointer
- fn data(&self) -> *const u8 {
- match self {
+ fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
+ let data_ptr = match self {
&ControlMessage::ScmRights(fds) => {
fds as *const _ as *const u8
},
@@ -738,7 +771,35 @@ impl<'a> ControlMessage<'a> {
&ControlMessage::ScmCredentials(creds) => {
creds as *const libc::ucred as *const u8
}
- }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetIv(iv) => {
+ unsafe {
+ let alg_iv = cmsg_data as *mut libc::af_alg_iv;
+ (*alg_iv).ivlen = iv.len() as u32;
+ ptr::copy_nonoverlapping(
+ iv.as_ptr(),
+ (*alg_iv).iv.as_mut_ptr(),
+ iv.len()
+ );
+ };
+ return
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetOp(op) => {
+ op as *const _ as *const u8
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetAeadAssoclen(len) => {
+ len as *const _ as *const u8
+ },
+ };
+ unsafe {
+ ptr::copy_nonoverlapping(
+ data_ptr,
+ cmsg_data,
+ self.len()
+ )
+ };
}
/// The size of the payload, excluding its cmsghdr
@@ -751,6 +812,18 @@ impl<'a> ControlMessage<'a> {
&ControlMessage::ScmCredentials(creds) => {
mem::size_of_val(creds)
}
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetIv(iv) => {
+ mem::size_of::<libc::af_alg_iv>() + iv.len()
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetOp(op) => {
+ mem::size_of_val(op)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetAeadAssoclen(len) => {
+ mem::size_of_val(len)
+ },
}
}
@@ -760,6 +833,10 @@ impl<'a> ControlMessage<'a> {
&ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetIv(_) | &ControlMessage::AlgSetOp(_) | &ControlMessage::AlgSetAeadAssoclen(_) => {
+ libc::SOL_ALG
+ },
}
}
@@ -769,6 +846,18 @@ impl<'a> ControlMessage<'a> {
&ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetIv(_) => {
+ libc::ALG_SET_IV
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetOp(_) => {
+ libc::ALG_SET_OP
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ &ControlMessage::AlgSetAeadAssoclen(_) => {
+ libc::ALG_SET_AEAD_ASSOCLEN
+ },
}
}
@@ -778,12 +867,7 @@ impl<'a> ControlMessage<'a> {
(*cmsg).cmsg_level = self.cmsg_level();
(*cmsg).cmsg_type = self.cmsg_type();
(*cmsg).cmsg_len = self.cmsg_len();
- let data = self.data();
- ptr::copy_nonoverlapping(
- data,
- CMSG_DATA(cmsg),
- self.len()
- );
+ self.copy_to_cmsg_data(CMSG_DATA(cmsg));
}
}
@@ -1098,6 +1182,8 @@ pub enum SockLevel {
Udp = libc::IPPROTO_UDP,
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink = libc::SOL_NETLINK,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Alg = libc::SOL_ALG,
}
/// Represents a socket option that can be accessed or set. Used as an argument
@@ -1111,7 +1197,7 @@ pub trait GetSockOpt : Copy {
/// Represents a socket option that can be accessed or set. Used as an argument
/// to `setsockopt`
-pub trait SetSockOpt : Copy {
+pub trait SetSockOpt : Clone {
type Val;
#[doc(hidden)]
@@ -1212,6 +1298,11 @@ pub unsafe fn sockaddr_storage_to_addr(
use libc::sockaddr_nl;
Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
}
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_ALG => {
+ use libc::sockaddr_alg;
+ Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg))))
+ }
af => panic!("unexpected address family {}", af),
}
}
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index 1920987e..a489eaff 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -307,6 +307,55 @@ sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[derive(Copy, Clone, Debug)]
+pub struct AlgSetAeadAuthSize;
+
+// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
+// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
+#[cfg(any(target_os = "android", target_os = "linux"))]
+impl SetSockOpt for AlgSetAeadAuthSize {
+ type Val = usize;
+
+ fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
+ unsafe {
+ let res = libc::setsockopt(fd,
+ libc::SOL_ALG,
+ libc::ALG_SET_AEAD_AUTHSIZE,
+ ::std::ptr::null(),
+ *val as libc::socklen_t);
+ Errno::result(res).map(drop)
+ }
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[derive(Clone, Debug)]
+pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+impl<T> Default for AlgSetKey<T> {
+ fn default() -> Self {
+ AlgSetKey(Default::default())
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
+ type Val = T;
+
+ fn set(&self, fd: RawFd, val: &T) -> Result<()> {
+ unsafe {
+ let res = libc::setsockopt(fd,
+ libc::SOL_ALG,
+ libc::ALG_SET_KEY,
+ val.as_ref().as_ptr() as *const _,
+ val.as_ref().len() as libc::socklen_t);
+ Errno::result(res).map(drop)
+ }
+ }
+}
+
/*
*
* ===== Accessor helpers =====
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index 5d55c87d..2790f681 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -186,6 +186,155 @@ pub fn test_scm_rights() {
close(w).unwrap();
}
+// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
+#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)]
+#[cfg(any(target_os = "linux", target_os= "android"))]
+#[test]
+pub fn test_af_alg_cipher() {
+ use libc;
+ use nix::sys::uio::IoVec;
+ use nix::unistd::read;
+ use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt,
+ AddressFamily, SockType, SockFlag, SockAddr,
+ ControlMessage, MsgFlags};
+ use nix::sys::socket::sockopt::AlgSetKey;
+
+ let alg_type = "skcipher";
+ let alg_name = "ctr(aes)";
+ // 256-bits secret key
+ let key = vec![0u8; 32];
+ // 16-bytes IV
+ let iv_len = 16;
+ let iv = vec![1u8; iv_len];
+ // 256-bytes plain payload
+ let payload_len = 256;
+ let payload = vec![2u8; payload_len];
+
+ let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None)
+ .expect("socket failed");
+
+ let sockaddr = SockAddr::new_alg(alg_type, alg_name);
+ bind(sock, &sockaddr).expect("bind failed");
+
+ if let SockAddr::Alg(alg) = sockaddr {
+ assert_eq!(alg.alg_name().to_string_lossy(), alg_name);
+ assert_eq!(alg.alg_type().to_string_lossy(), alg_type);
+ } else {
+ panic!("unexpected SockAddr");
+ }
+
+ setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt");
+ let session_socket = accept(sock).expect("accept failed");
+
+ let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())];
+ let iov = IoVec::from_slice(&payload);
+ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt");
+
+ // allocate buffer for encrypted data
+ let mut encrypted = vec![0u8; payload_len];
+ let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
+ assert_eq!(num_bytes, payload_len);
+
+ let iov = IoVec::from_slice(&encrypted);
+
+ let iv = vec![1u8; iv_len];
+
+ let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice())];
+ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt");
+
+ // allocate buffer for decrypted data
+ let mut decrypted = vec![0u8; payload_len];
+ let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
+
+ assert_eq!(num_bytes, payload_len);
+ assert_eq!(decrypted, payload);
+}
+
+// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
+#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)]
+#[cfg(any(target_os = "linux", target_os= "android"))]
+#[test]
+pub fn test_af_alg_aead() {
+ use libc;
+ use nix::sys::uio::IoVec;
+ use nix::unistd::{read, close};
+ use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt,
+ AddressFamily, SockType, SockFlag, SockAddr,
+ ControlMessage, MsgFlags};
+ use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize};
+
+ let auth_size = 4usize;
+ let assoc_size = 16u32;
+
+ let alg_type = "aead";
+ let alg_name = "gcm(aes)";
+ // 256-bits secret key
+ let key = vec![0u8; 32];
+ // 12-bytes IV
+ let iv_len = 12;
+ let iv = vec![1u8; iv_len];
+ // 256-bytes plain payload
+ let payload_len = 256;
+ let mut payload = vec![2u8; payload_len + (assoc_size as usize) + auth_size];
+
+ for i in 0..assoc_size {
+ payload[i as usize] = 10;
+ }
+
+ let len = payload.len();
+
+ for i in 0..auth_size {
+ payload[len - 1 - i] = 0;
+ }
+
+ let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None)
+ .expect("socket failed");
+
+ let sockaddr = SockAddr::new_alg(alg_type, alg_name);
+ bind(sock, &sockaddr).expect("bind failed");
+
+ setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize");
+ setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey");
+ let session_socket = accept(sock).expect("accept failed");
+
+ let msgs = [
+ ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT),
+ ControlMessage::AlgSetIv(iv.as_slice()),
+ ControlMessage::AlgSetAeadAssoclen(&assoc_size)];
+ let iov = IoVec::from_slice(&payload);
+ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt");
+
+ // allocate buffer for encrypted data
+ let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size];
+ let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
+ assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));
+ close(session_socket).expect("close");
+
+ for i in 0..assoc_size {
+ encrypted[i as usize] = 10;
+ }
+
+ let iov = IoVec::from_slice(&encrypted);
+
+ let iv = vec![1u8; iv_len];
+
+ let session_socket = accept(sock).expect("accept failed");
+
+ let msgs = [
+ ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT),
+ ControlMessage::AlgSetIv(iv.as_slice()),
+ ControlMessage::AlgSetAeadAssoclen(&assoc_size),
+ ];
+ sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt");
+
+ // allocate buffer for decrypted data
+ let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size];
+ let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
+
+ assert!(num_bytes >= payload_len + (assoc_size as usize));
+ assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]);
+}
+
/// Tests that passing multiple fds using a single `ControlMessage` works.
// Disable the test on emulated platforms due to a bug in QEMU versions <
// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808