Skip to main content

kcapi/
lib.rs

1/*
2 * $Id$
3 *
4 * Copyright (c) 2021, Purushottam A. Kulkarni.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation and
15 * or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its contributors
18 * may be used to endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE
32 *
33 */
34
35//!
36//! # `kcapi` - The Official High-level Rust Bindings for `libkcapi`
37//!
38//! This crate provides the official high-level Rust bindings for `libkcapi`.
39//! The goal of this crate is to provide a rusty API to the C library `libkcapi`,
40//! which itself provides consumers the capability to access the Linux Kernel's
41//! Cryptographic API (KCAPI) from userland to perform cryptographic requests.
42//!
43//! This is a permissively (BSD-3-Clause) licensed crate which can be included
44//! in your applications to remove dependence on OpenSSL or other cryptographic
45//! libraries, and use the Linux KCAPI instead.
46//!
47//! # Layout
48//!
49//! This crate is divided into the following modules:
50//!
51//! * `md` - Message digest API.
52//! * `skcipher` - Symmetric key cipher API.
53//! * `aead` - Authenticated Encryption with Associated Data (AEAD) API.
54//! * `rng` - Random Number Generation (RNG) API.
55//! * `akcipher` - Asymmetric key cipher API.
56//! * `kdf` - Key Derivation Function API.
57//! * `kpp` - Key Protocol Primitives (DH / ECDH) API.
58//!
59//! Each of these modules specify their own unique context type. For instance,
60//! the `skcipher` module provides the `KcapiSKCipher` context type, which
61//! can be used to perform encryption/decryption and other operations.
62//!
63//! This crate defines a `KcapiResult` type which can be used to encapsulate
64//! output from any consumers of this API, and also propagate errors to callers.
65//!
66//! This crate also defines a custom error type `KcapiError` which implements
67//! the `fmt::Display` trait.
68//!
69//! This crate also provides the `IOVec` type, which can be used to represent
70//! a Linux Kernel Scatter/Gather list of `u8`s.
71//!
72//! # Pre-requisites
73//!
74//! This crate requires the Linux Kernel to be compiled with the following options:
75//!
76//! * `CONFIG_CRYPTO_USER=m` - Compile the `af_alg.ko` module.
77//! * `CONFIG_CRYPTO_USER_API=y` - Enable Userland crypto API.
78//! * `CONFIG_CRYPTO_USER_API_HASH=y` - Enable the hash API.
79//! * `CONFIG_CRYPTO_USER_API_SKCIPHER=y` - Enable the Symmetric cipher API.
80//! * `CONFIG_CRYPTO_USER_API_RNG=y` - Enable the RNG API.
81//! * `CONFIG_CRYPTO_USER_API_AEAD=y` - Enable the AEAD API.
82//!
83//! If you wish to perform Cryptographic Algorithm Validation Program (CAVP)
84//! testing on the RNG, then you must also enable the following option.
85//!
86//! * `CONFIG_CRYPTO_USER_API_RNG_CAVP=y` - Enable RNG CAVP testing from userland.
87//!
88//! After the patches in the `kernel-patches` directory of this crate are applied,
89//! the following config option can also be enabled:
90//!
91//! * `CONFIG_CRYPTO_USER_API_AKCIPHER=y` - Enable the Asymmetric cipher API.
92//!
93//! Once these configuration options are enabled in the Linux Kernel, and the
94//! compilation succeeds, you may use this crate to it's full potential.
95//!
96
97use std::fmt;
98
99const BITS_PER_BYTE: usize = 8;
100
101///
102/// Fastest kernel access using internal heuristics.
103///
104pub const ACCESS_HEURISTIC: u32 = kcapi_sys::KCAPI_ACCESS_HEURISTIC;
105
106///
107/// Linux Kernel `sendmsg(2)` API access. See `man 2 sendmsg`.
108///
109pub const ACCESS_SENDMSG: u32 = kcapi_sys::KCAPI_ACCESS_SENDMSG;
110
111///
112/// Linux Kernel VMSplice Access
113///
114pub const ACCESS_VMSPLICE: u32 = kcapi_sys::KCAPI_ACCESS_VMSPLICE;
115
116///
117/// Use Kernel Asynchronous I/O interface if it is available.
118///
119pub const INIT_AIO: u32 = kcapi_sys::KCAPI_INIT_AIO;
120
121///
122/// # The `KcapiResult<T>` Type
123///
124/// This type defines a result which is returned from a majority
125/// of the APIs in this crate. At a high level, it is an `enum` of
126/// `Ok(T)`, and `Err(KcapiError)`.
127///
128/// ```
129/// use kcapi::KcapiError;
130///
131/// enum KcapiResult<T> {
132///     Ok(T),
133///     Err(KcapiError),
134/// };
135/// ```
136///
137/// You can match against these when calling an API which returns
138/// the `KcapiResult` type.
139///
140pub type KcapiResult<T> = std::result::Result<T, KcapiError>;
141
142///
143/// # The `KcapiError` Type
144///
145/// This type defines an error returned from the `kcapi` crate.
146/// This type has two fields:
147/// * `code` - The error code returned by the Kernel
148/// * `message` - A string representation of what went wrong.
149///
150/// This error type also implements a `fmt::Display` method, which can
151/// be used to print out the exact error which occured.
152///
153#[derive(Debug, Clone)]
154pub struct KcapiError {
155    pub code: i32,
156    pub message: String,
157}
158
159impl fmt::Display for KcapiError {
160    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161        write!(f, "{} ({})", &self.message, &self.code)
162    }
163}
164
165impl std::error::Error for KcapiError {}
166
167#[repr(C)]
168#[derive(Debug, Clone, Copy)]
169struct kcapi_handle {
170    _unused: [u8; 0],
171}
172
173///
174/// # The `IOVec` type
175///
176/// This type is used to represent a Linux Kernel scatter/gather list.
177/// At a high level, this type accepts a `Vec<Vec<u8>>` and creates a scatter/gather
178/// list from that.
179///
180/// This type also implements the following methods:
181/// * `len()` - Return the number of entries in the scatter/gather list.
182/// * `is_emtpy()` - Return whether the scatter/gather list is empty.
183/// * `push()` - Add an entry to an existing scatter/gather list.
184/// * `pop()` - Try to pop an entry from an existing scatter/gather list.
185///
186#[derive(Debug, Clone)]
187pub struct IOVec<T> {
188    iovec: Vec<kcapi_sys::iovec>,
189    iovlen: usize,
190    data: Vec<T>,
191}
192
193pub trait IOVecTrait<T> {
194    fn new(iov: Vec<T>) -> KcapiResult<Self>
195    where
196        Self: Sized;
197    fn len(&self) -> usize;
198    fn is_empty(&self) -> bool;
199    fn push(&mut self, buf: T);
200    fn pop(&mut self) -> Option<T>;
201}
202
203impl IOVecTrait<Vec<u8>> for IOVec<Vec<u8>> {
204    ///
205    /// ## Initialize an instance of type `IOVec`
206    ///
207    /// This function creates a Linux kernel scatterlist from a `Vec<Vec<T>>`.
208    /// The scaterlest is stored in the `iovec` field of the returned `IOVec`.
209    ///
210    /// This function takes:
211    /// * `iov` - A `Vec<Vec<u8>>` containing buffers to add to the scatterlist
212    ///
213    /// On success, an initialized instance of type `IOVec` is returned.
214    /// On failure, a `KcapiError` is returned.
215    ///
216    /// ## Examples
217    ///
218    /// ```
219    /// use kcapi::{IOVec, IOVecTrait};
220    ///
221    /// let mut sg = vec![vec![0xff; 16]; 16];
222    /// let iovec = IOVec::new(sg)
223    ///     .expect("Failed to intialize an IOVec");
224    ///
225    /// assert_eq!(iovec.len(), 16);
226    /// ```
227    ///
228    fn new(iov: Vec<Vec<u8>>) -> KcapiResult<Self> {
229        if iov.is_empty() {
230            return Err(KcapiError {
231                code: -libc::EINVAL,
232                message: format!(
233                    "Cannot create an IOVec from a vector of length {}",
234                    iov.len(),
235                ),
236            });
237        }
238
239        let mut iovec = Vec::new();
240        let ilen = iov.len();
241        let mut data = iov;
242        for i in data.iter_mut().take(ilen) {
243            iovec.push(kcapi_sys::iovec {
244                iov_base: i.as_mut_ptr() as *mut ::std::os::raw::c_void,
245                iov_len: i.len() as kcapi_sys::size_t,
246            });
247        }
248        let iovlen = iovec.len();
249        Ok(IOVec {
250            iovec,
251            iovlen,
252            data,
253        })
254    }
255
256    ///
257    /// ## Obtain the length of the `IOVec` instance.
258    ///
259    /// This function returns the length of an initialized `IOVec`.
260    ///
261    fn len(&self) -> usize {
262        self.iovlen
263    }
264
265    ///
266    /// ## Determine whether the `IOVec` is empty.
267    ///
268    /// This function returns `true` if the `IOVec` instance is empty.
269    ///
270    fn is_empty(&self) -> bool {
271        if self.iovlen == 0 {
272            return true;
273        }
274        false
275    }
276
277    ///
278    /// ## Push a buffer into the `IOVec`
279    ///
280    /// This function is used to add a `Vec<u8>` to an existing scatter/gather
281    /// list represented by an `IOVec`.
282    ///
283    /// ## Examples
284    ///
285    /// ```
286    /// use kcapi::{IOVec, IOVecTrait};
287    ///
288    /// let mut sg = vec![vec![0xff; 16]; 16];
289    /// let mut iovec = IOVec::new(sg)
290    ///     .expect("Failed to initialize an IOVec");
291    ///
292    /// iovec.push(vec![0x41; 16]);
293    /// ```
294    ///
295    fn push(&mut self, buf: Vec<u8>) {
296        let mut bufp = buf;
297        self.iovec.push(kcapi_sys::iovec {
298            iov_base: bufp.as_mut_ptr() as *mut ::std::os::raw::c_void,
299            iov_len: bufp.len() as kcapi_sys::size_t,
300        });
301        self.iovlen += 1;
302    }
303
304    ///
305    /// ## Pop a buffer from an `IOVec`
306    ///
307    /// This function is used to pop a `Vec<u8>` from an existing scatter/gather
308    /// list represented by an `IOVec`.
309    ///
310    /// An `Option<Vec<u8>>` is returned if the `IOVec` has any data that can be
311    /// popped. If the `IOVec` is empty, then `None` is returned.
312    ///
313    /// ## Examples
314    ///
315    /// ```
316    /// use kcapi::{IOVec, IOVecTrait};
317    ///
318    /// let mut sg = vec![vec![0xff; 16]; 16];
319    /// let mut iovec = IOVec::new(sg)
320    ///     .expect("Failed to initialize an IOVec");
321    ///
322    /// if let Some(buf) = iovec.pop() {
323    ///     println!("{:#?}", buf);
324    /// }
325    /// ```
326    ///
327    fn pop(&mut self) -> Option<Vec<u8>> {
328        if let Some(_i) = self.iovec.pop() {
329            self.iovlen -= 1;
330            let out = self.data.pop();
331            return out;
332        }
333        None
334    }
335}
336
337pub trait VMSplice {
338    fn get_max_splicesize(&self) -> usize;
339    fn set_max_splicesize(&self, size: usize) -> KcapiResult<()>;
340}
341
342pub mod util;
343
344pub mod aead;
345#[cfg(feature = "asym")]
346pub mod akcipher;
347pub mod kdf;
348#[cfg(feature = "kpp")]
349pub mod kpp;
350pub mod md;
351pub mod rng;
352pub mod skcipher;
353mod test;