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;