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//!
58//! Each of these modules specify their own unique context type. For instance,
59//! the `skcipher` module provides the `KcapiSKCipher` context type, which
60//! can be used to perform encryption/decryption and other operations.
61//!
62//! This crate defines a `KcapiResult` type which can be used to encapsulate
63//! output from any consumers of this API, and also propagate errors to callers.
64//!
65//! This crate also defines a custom error type `KcapiError` which implements
66//! the `fmt::Display` trait.
67//!
68//! This crate also provides the `IOVec` type, which can be used to represent
69//! a Linux Kernel Scatter/Gather list of `u8`s.
70//!
71//! # Pre-requisites
72//!
73//! This crate requires the Linux Kernel to be compiled with the following options:
74//!
75//! * `CONFIG_CRYPTO_USER=m` - Compile the `af_alg.ko` module.
76//! * `CONFIG_CRYPTO_USER_API=y` - Enable Userland crypto API.
77//! * `CONFIG_CRYPTO_USER_API_HASH=y` - Enable the hash API.
78//! * `CONFIG_CRYPTO_USER_API_SKCIPHER=y` - Enable the Symmetric cipher API.
79//! * `CONFIG_CRYPTO_USER_API_RNG=y` - Enable the RNG API.
80//! * `CONFIG_CRYPTO_USER_API_AEAD=y` - Enable the AEAD API.
81//!
82//! If you wish to perform Cryptographic Algorithm Validation Program (CAVP)
83//! testing on the RNG, then you must also enable the following option.
84//!
85//! * `CONFIG_CRYPTO_USER_API_RNG_CAVP=y` - Enable RNG CAVP testing from userland.
86//!
87//! After the patches in the `kernel-patches` directory of this crate are applied,
88//! the following config option can also be enabled:
89//!
90//! * `CONFIG_CRYPTO_USER_API_AKCIPHER=y` - Enable the Asymmetric cipher API.
91//!
92//! Once these configuration options are enabled in the Linux Kernel, and the
93//! compilation succeeds, you may use this crate to it's full potential.
94//!
95
96use std::fmt;
97
98const BITS_PER_BYTE: usize = 8;
99
100///
101/// Fastest kernel access using internal heuristics.
102///
103pub const ACCESS_HEURISTIC: u32 = kcapi_sys::KCAPI_ACCESS_HEURISTIC;
104
105///
106/// Linux Kernel `sendmsg(2)` API access. See `man 2 sendmsg`.
107///
108pub const ACCESS_SENDMSG: u32 = kcapi_sys::KCAPI_ACCESS_SENDMSG;
109
110///
111/// Linux Kernel VMSplice Access
112///
113pub const ACCESS_VMSPLICE: u32 = kcapi_sys::KCAPI_ACCESS_VMSPLICE;
114
115///
116/// Use Kernel Asynchronous I/O interface if it is available.
117///
118pub const INIT_AIO: u32 = kcapi_sys::KCAPI_INIT_AIO;
119
120///
121/// # The `KcapiResult<T>` Type
122///
123/// This type defines a result which is returned from a majority
124/// of the APIs in this crate. At a high level, it is an `enum` of
125/// `Ok(T)`, and `Err(KcapiError)`.
126///
127/// ```
128/// use kcapi::KcapiError;
129///
130/// enum KcapiResult<T> {
131///     Ok(T),
132///     Err(KcapiError),
133/// };
134/// ```
135///
136/// You can match against these when calling an API which returns
137/// the `KcapiResult` type.
138///
139pub type KcapiResult<T> = std::result::Result<T, KcapiError>;
140
141///
142/// # The `KcapiError` Type
143///
144/// This type defines an error returned from the `kcapi` crate.
145/// This type has two fields:
146/// * `code` - The error code returned by the Kernel
147/// * `message` - A string representation of what went wrong.
148///
149/// This error type also implements a `fmt::Display` method, which can
150/// be used to print out the exact error which occured.
151///
152#[derive(Debug, Clone)]
153pub struct KcapiError {
154    pub code: i32,
155    pub message: String,
156}
157
158impl fmt::Display for KcapiError {
159    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160        write!(f, "{} ({})", &self.message, &self.code)
161    }
162}
163
164#[repr(C)]
165#[derive(Debug, Clone, Copy)]
166struct kcapi_handle {
167    _unused: [u8; 0],
168}
169
170///
171/// # The `IOVec` type
172///
173/// This type is used to represent a Linux Kernel scatter/gather list.
174/// At a high level, this type accepts a `Vec<Vec<u8>>` and creates a scatter/gather
175/// list from that.
176///
177/// This type also implements the following methods:
178/// * `len()` - Return the number of entries in the scatter/gather list.
179/// * `is_emtpy()` - Return whether the scatter/gather list is empty.
180/// * `push()` - Add an entry to an existing scatter/gather list.
181/// * `pop()` - Try to pop an entry from an existing scatter/gather list.
182///
183#[derive(Debug, Clone)]
184pub struct IOVec<T> {
185    iovec: Vec<kcapi_sys::iovec>,
186    iovlen: usize,
187    data: Vec<T>,
188}
189
190pub trait IOVecTrait<T> {
191    fn new(iov: Vec<T>) -> KcapiResult<Self>
192    where
193        Self: Sized;
194    fn len(&self) -> usize;
195    fn is_empty(&self) -> bool;
196    fn push(&mut self, buf: T);
197    fn pop(&mut self) -> Option<T>;
198}
199
200impl IOVecTrait<Vec<u8>> for IOVec<Vec<u8>> {
201    ///
202    /// ## Initialize an instance of type `IOVec`
203    ///
204    /// This function creates a Linux kernel scatterlist from a `Vec<Vec<T>>`.
205    /// The scaterlest is stored in the `iovec` field of the returned `IOVec`.
206    ///
207    /// This function takes:
208    /// * `iov` - A `Vec<Vec<u8>>` containing buffers to add to the scatterlist
209    ///
210    /// On success, an initialized instance of type `IOVec` is returned.
211    /// On failure, a `KcapiError` is returned.
212    ///
213    /// ## Examples
214    ///
215    /// ```
216    /// use kcapi::{IOVec, IOVecTrait};
217    ///
218    /// let mut sg = vec![vec![0xff; 16]; 16];
219    /// let iovec = IOVec::new(sg)
220    ///     .expect("Failed to intialize an IOVec");
221    ///
222    /// assert_eq!(iovec.len(), 16);
223    /// ```
224    ///
225    fn new(iov: Vec<Vec<u8>>) -> KcapiResult<Self> {
226        if iov.is_empty() {
227            return Err(KcapiError {
228                code: -libc::EINVAL,
229                message: format!(
230                    "Cannot create an IOVec from a vector of length {}",
231                    iov.len(),
232                ),
233            });
234        }
235
236        let mut iovec = Vec::new();
237        let ilen = iov.len();
238        let mut data = iov;
239        for i in data.iter_mut().take(ilen) {
240            iovec.push(kcapi_sys::iovec {
241                iov_base: i.as_mut_ptr() as *mut ::std::os::raw::c_void,
242                iov_len: i.len() as kcapi_sys::size_t,
243            });
244        }
245        let iovlen = iovec.len();
246        Ok(IOVec {
247            iovec,
248            iovlen,
249            data,
250        })
251    }
252
253    ///
254    /// ## Obtain the length of the `IOVec` instance.
255    ///
256    /// This function returns the length of an initialized `IOVec`.
257    ///
258    fn len(&self) -> usize {
259        self.iovlen
260    }
261
262    ///
263    /// ## Determine whether the `IOVec` is empty.
264    ///
265    /// This function returns `true` if the `IOVec` instance is empty.
266    ///
267    fn is_empty(&self) -> bool {
268        if self.iovlen == 0 {
269            return true;
270        }
271        false
272    }
273
274    ///
275    /// ## Push a buffer into the `IOVec`
276    ///
277    /// This function is used to add a `Vec<u8>` to an existing scatter/gather
278    /// list represented by an `IOVec`.
279    ///
280    /// ## Examples
281    ///
282    /// ```
283    /// use kcapi::{IOVec, IOVecTrait};
284    ///
285    /// let mut sg = vec![vec![0xff; 16]; 16];
286    /// let mut iovec = IOVec::new(sg)
287    ///     .expect("Failed to initialize an IOVec");
288    ///
289    /// iovec.push(vec![0x41; 16]);
290    /// ```
291    ///
292    fn push(&mut self, buf: Vec<u8>) {
293        let mut bufp = buf;
294        self.iovec.push(kcapi_sys::iovec {
295            iov_base: bufp.as_mut_ptr() as *mut ::std::os::raw::c_void,
296            iov_len: bufp.len() as kcapi_sys::size_t,
297        });
298        self.iovlen += 1;
299    }
300
301    ///
302    /// ## Pop a buffer from an `IOVec`
303    ///
304    /// This function is used to pop a `Vec<u8>` from an existing scatter/gather
305    /// list represented by an `IOVec`.
306    ///
307    /// An `Option<Vec<u8>>` is returned if the `IOVec` has any data that can be
308    /// popped. If the `IOVec` is empty, then `None` is returned.
309    ///
310    /// ## Examples
311    ///
312    /// ```
313    /// use kcapi::{IOVec, IOVecTrait};
314    ///
315    /// let mut sg = vec![vec![0xff; 16]; 16];
316    /// let mut iovec = IOVec::new(sg)
317    ///     .expect("Failed to initialize an IOVec");
318    ///
319    /// if let Some(buf) = iovec.pop() {
320    ///     println!("{:#?}", buf);
321    /// }
322    /// ```
323    ///
324    fn pop(&mut self) -> Option<Vec<u8>> {
325        if let Some(_i) = self.iovec.pop() {
326            self.iovlen -= 1;
327            let out = self.data.pop();
328            return out;
329        }
330        None
331    }
332}
333
334pub trait VMSplice {
335    fn get_max_splicesize(&self) -> usize;
336    fn set_max_splicesize(&self, size: usize) -> KcapiResult<()>;
337}
338
339pub mod util;
340
341pub mod aead;
342#[cfg(feature = "asym")]
343pub mod akcipher;
344pub mod kdf;
345pub mod md;
346pub mod rng;
347pub mod skcipher;
348mod test;