Skip to content

Commit bc80369

Browse files
author
Gleb Pomykalov
committed
AEAD support and several types fixes. Temporary use forked version of libc, until the fix is merged.
1 parent 34217e0 commit bc80369

File tree

4 files changed

+125
-30
lines changed

4 files changed

+125
-30
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ exclude = [
1616
]
1717

1818
[dependencies]
19-
libc = { git = "https://github.com/rust-lang/libc" }
19+
libc = { git = "https://github.com/glebpom/libc", rev = "crypto-api-constant-types-fix" }
2020
bitflags = "1.0"
2121
cfg-if = "0.1.0"
2222
void = "1.0.2"

src/sys/socket/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ pub enum ControlMessage<'a> {
721721
target_os = "android",
722722
target_os = "linux",
723723
))]
724-
AlgSetOp(&'a c_int),
724+
AlgSetOp(&'a u32),
725725
/// Set the length of associated authentication data (AAD) (applicable only to AEAD algoritms)
726726
/// for `AF_ALG` crypto API.
727727
/// AF_ALG is only supported on linux and android.
@@ -731,7 +731,7 @@ pub enum ControlMessage<'a> {
731731
target_os = "android",
732732
target_os = "linux",
733733
))]
734-
AlgSetAeadAssoclen(&'a c_int),
734+
AlgSetAeadAssoclen(&'a u32),
735735

736736
}
737737

@@ -1199,7 +1199,7 @@ pub trait GetSockOpt : Copy {
11991199

12001200
/// Represents a socket option that can be accessed or set. Used as an argument
12011201
/// to `setsockopt`
1202-
pub trait SetSockOpt : Copy {
1202+
pub trait SetSockOpt : Clone {
12031203
type Val;
12041204

12051205
#[doc(hidden)]

src/sys/socket/sockopt.rs

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,6 @@ macro_rules! sockopt_impl {
148148
sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
149149
};
150150

151-
(SetOnly, $name:ident, $level:path, $flag:path, [u8]) => {
152-
sockopt_impl!(SetOnly, $name, $level, $flag, [u8], SetBytes<[u8]>);
153-
};
154-
155151
(Both, $name:ident, $level:path, $flag:path, bool) => {
156152
sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
157153
};
@@ -223,7 +219,6 @@ cfg_if! {
223219
if #[cfg(any(target_os = "android", target_os = "linux"))] {
224220
sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
225221
sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
226-
sockopt_impl!(SetOnly, AlgSetKey, libc::SOL_ALG, libc::ALG_SET_KEY, Vec<u8>);
227222
} else if #[cfg(any(target_os = "dragonfly",
228223
target_os = "freebsd",
229224
target_os = "ios",
@@ -312,6 +307,55 @@ sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
312307
sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
313308

314309

310+
#[cfg(any(target_os = "android", target_os = "linux"))]
311+
#[derive(Copy, Clone, Debug)]
312+
pub struct AlgSetAeadAuthSize;
313+
314+
// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
315+
// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
316+
#[cfg(any(target_os = "android", target_os = "linux"))]
317+
impl SetSockOpt for AlgSetAeadAuthSize {
318+
type Val = usize;
319+
320+
fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
321+
unsafe {
322+
let res = libc::setsockopt(fd,
323+
libc::SOL_ALG,
324+
libc::ALG_SET_AEAD_AUTHSIZE,
325+
::std::ptr::null(),
326+
*val as libc::socklen_t);
327+
Errno::result(res).map(drop)
328+
}
329+
}
330+
}
331+
332+
#[cfg(any(target_os = "android", target_os = "linux"))]
333+
#[derive(Clone, Debug)]
334+
pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
335+
336+
#[cfg(any(target_os = "android", target_os = "linux"))]
337+
impl<T> Default for AlgSetKey<T> {
338+
fn default() -> Self {
339+
AlgSetKey(Default::default())
340+
}
341+
}
342+
343+
#[cfg(any(target_os = "android", target_os = "linux"))]
344+
impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
345+
type Val = T;
346+
347+
fn set(&self, fd: RawFd, val: &T) -> Result<()> {
348+
unsafe {
349+
let res = libc::setsockopt(fd,
350+
libc::SOL_ALG,
351+
libc::ALG_SET_KEY,
352+
val.as_ref().as_ptr() as *const _,
353+
val.as_ref().len() as libc::socklen_t);
354+
Errno::result(res).map(drop)
355+
}
356+
}
357+
}
358+
315359
/*
316360
*
317361
* ===== Accessor helpers =====
@@ -372,25 +416,6 @@ unsafe impl<T> Get<T> for GetStruct<T> {
372416
}
373417
}
374418

375-
/// Setter for bytes.
376-
struct SetBytes<'a, T> where T: 'a + AsRef<[u8]> {
377-
ptr: &'a T,
378-
}
379-
380-
unsafe impl<'a, T> Set<'a, T> for SetBytes<'a, T> where T: AsRef<[u8]> {
381-
fn new(ptr: &'a T) -> SetBytes<'a, T> {
382-
SetBytes { ptr }
383-
}
384-
385-
fn ffi_ptr(&self) -> *const c_void {
386-
self.ptr.as_ref() as *const _ as *const c_void
387-
}
388-
389-
fn ffi_len(&self) -> socklen_t {
390-
self.ptr.as_ref().len() as socklen_t
391-
}
392-
}
393-
394419
/// Setter for an arbitrary `struct`.
395420
struct SetStruct<'a, T: 'static> {
396421
ptr: &'a T,

test/sys/test_socket.rs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ pub fn test_scm_rights() {
188188

189189
#[cfg(any(target_os = "linux", target_os= "android"))]
190190
#[test]
191-
pub fn test_af_alg_cmsg() {
191+
pub fn test_af_alg_cipher() {
192192
use libc;
193193
use nix::sys::uio::IoVec;
194194
use nix::unistd::read;
@@ -221,7 +221,7 @@ pub fn test_af_alg_cmsg() {
221221
panic!("unexpected SockAddr");
222222
}
223223

224-
setsockopt(sock, AlgSetKey, &key).expect("setsockopt");
224+
setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt");
225225
let session_socket = accept(sock).expect("accept failed");
226226

227227
let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())];
@@ -248,6 +248,76 @@ pub fn test_af_alg_cmsg() {
248248
assert_eq!(decrypted, payload);
249249
}
250250

251+
#[cfg(any(target_os = "linux", target_os= "android"))]
252+
#[test]
253+
pub fn test_af_alg_aead() {
254+
use libc;
255+
use nix::sys::uio::IoVec;
256+
use nix::unistd::read;
257+
use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt,
258+
AddressFamily, SockType, SockFlag, SockAddr,
259+
ControlMessage, MsgFlags};
260+
use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize};
261+
262+
let auth_size = 4usize;
263+
let assoc_size = 16u32;
264+
265+
let alg_type = "aead";
266+
let alg_name = "gcm(aes)";
267+
// 256-bits secret key
268+
let key = vec![0u8; 32];
269+
// 12-bytes IV
270+
let iv_len = 12;
271+
let iv = vec![1u8; iv_len];
272+
// 256-bytes plain payload
273+
let payload_len = 256;
274+
let mut payload = vec![2u8; payload_len + (assoc_size as usize)];
275+
276+
for i in 0..assoc_size {
277+
payload[i as usize] = 10;
278+
}
279+
280+
let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None)
281+
.expect("socket failed");
282+
283+
let sockaddr = SockAddr::new_alg(alg_type, alg_name);
284+
bind(sock, &sockaddr).expect("bind failed");
285+
286+
setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey");
287+
setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize");
288+
let session_socket = accept(sock).expect("accept failed");
289+
290+
let msgs = [
291+
ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT),
292+
ControlMessage::AlgSetIv(iv.as_slice()),
293+
ControlMessage::AlgSetAeadAssoclen(&assoc_size)];
294+
let iov = IoVec::from_slice(&payload);
295+
sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt");
296+
297+
// allocate buffer for encrypted data
298+
let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size];
299+
let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
300+
assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));
301+
302+
let iov = IoVec::from_slice(&encrypted);
303+
304+
let iv = vec![1u8; iv_len];
305+
306+
let msgs = [
307+
ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT),
308+
ControlMessage::AlgSetIv(iv.as_slice()),
309+
ControlMessage::AlgSetAeadAssoclen(&assoc_size),
310+
];
311+
sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt");
312+
313+
// allocate buffer for decrypted data
314+
let mut decrypted = vec![0u8; payload_len + (assoc_size as usize)];
315+
let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
316+
317+
assert_eq!(num_bytes, payload_len + (assoc_size as usize));
318+
assert_eq!(decrypted, payload);
319+
}
320+
251321
/// Tests that passing multiple fds using a single `ControlMessage` works.
252322
// Disable the test on emulated platforms due to a bug in QEMU versions <
253323
// 2.12.0. https://bugs.launchpad.net/qemu/+bug/1701808

0 commit comments

Comments
 (0)