kcapi/
akcipher.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//! # Asymmetric Key Ciphers (akcipher) using the Kernel Crypto API
37//!
38//! This module is **EXPERIMENTAL**
39//!
40//! This module provides the capability to perform asymmetric key encryption,
41//! decryption, signing, and verification using the KCAPI provided the following
42//! conditions are met:
43//!
44//! 1. The patches in the `kernel-patches` directory are successfully applied.
45//! 2. The kernel is compiled with `CONFIG_CRYPTO_USER_API_AKCIPHER=y`
46//!
47//! *Note:* Any asymmetric key cipher used with this module **MUST** be present
48//! in `/proc/crypto` on the target device.
49//!
50//! # Layout
51//!
52//! This module provides one-shot convenience functions to perform encryption,
53//! decryption, signing, and verification using any AK cipher present in
54//! `/proc/crypto`. This module also provides the `KcapiAKCipher` type which
55//! provides APIs to initialize, set public and private keys, encrypt, decrypt,
56//! sign, and verify using the appropriate algorithm from `/proc/crypto`.
57//!
58//!
59//! ## Caveats
60//!
61//! Since the support to perform asymmetric cipher operations from userland is
62//! not present in the upstream Linux kernel, this module is still **EXPERIMENTAL**.
63//! This module is **only** available when the `asym` feature is enabled.
64//! This is because the `akcipher_*` APIs are available only when `libkcapi` is configured
65//! to have them.
66//!
67//! **WARNING**: Prior to using this API with the `local-kcapi` feature enabled,
68//! ensure that you have `lib-asym` configured for your `libkcapi` installation.
69//!
70
71use std::{convert::TryInto, ffi::CString};
72
73use crate::{KcapiError, KcapiResult, VMSplice, ACCESS_HEURISTIC, INIT_AIO};
74
75///
76/// # The `KcapiAKCipher` Type
77///
78/// This type denotes a generic context for an Asymmetric Key cipher transform
79/// in the Linux Kernel. An instance of this struct must be initialized using
80/// the `new()` call prior to being used. This type provides APIs to perform:
81///
82/// * setting of public and private keys.
83/// * encryption
84/// * decryption
85/// * signing
86/// * verification
87///
88/// ## Panics
89///
90/// If the string provided as input to the `new()` function cannot be converted into a
91/// `std::ffi::CString` type, the initialization will panic with the message
92/// `Failed to create CString`.
93///
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct KcapiAKCipher {
96    handle: *mut kcapi_sys::kcapi_handle,
97    pubkey: Vec<u8>,
98    privkey: Vec<u8>,
99    pub modsize: usize,
100    pub algorithm: String,
101}
102
103impl KcapiAKCipher {
104    ///
105    /// ## Initialize an instance of the `KcapiAKCipher` Type.
106    ///
107    /// This function initializes an instance of the `KcapiAKCipher` Type and
108    /// makes the necessary connections to the kernel through `kcapi-sys`.
109    ///
110    /// This function takes:
111    /// * `algorithm` - a `&str` representation of an `akcipher` algorithm in `/proc/crypto`
112    /// * `flags` - `u32` flags specifying the type of cipher handle.
113    ///
114    /// On success, an initialized instance of `KcapiAKCipher` is returned.
115    /// On failure, a `KcapiError` is returned.
116    ///
117    pub fn new(algorithm: &str, flags: u32) -> KcapiResult<Self> {
118        let mut handle = Box::into_raw(Box::new(crate::kcapi_handle { _unused: [0u8; 0] }))
119            as *mut kcapi_sys::kcapi_handle;
120        let pubkey = Vec::<u8>::new();
121        let privkey = Vec::<u8>::new();
122
123        let alg = CString::new(algorithm).expect("Failed to create CString");
124        unsafe {
125            let ret = kcapi_sys::kcapi_akcipher_init(&mut handle as *mut _, alg.as_ptr(), flags);
126            if ret < 0 {
127                return Err(KcapiError {
128                    code: ret,
129                    message: format!(
130                        "Failed to initialize akcipher handle for algorithm '{}'",
131                        algorithm
132                    ),
133                });
134            }
135        }
136
137        Ok(KcapiAKCipher {
138            algorithm: algorithm.to_string(),
139            handle,
140            modsize: 0,
141            pubkey,
142            privkey,
143        })
144    }
145
146    ///
147    /// ## Set the Private Key
148    ///
149    /// This function is used to set the private key for decryption and
150    /// signing operations.
151    ///
152    /// The key must be a `Vec<u8>` in DER format as follows:
153    ///
154    /// ```none
155    /// SEQUENCE {
156    ///     version INTEGER,
157    ///     n INTEGER ({ rsa_get_n }),
158    ///     e INTEGER ({ rsa_get_e }),
159    ///     d INTEGER ({ rsa_get_d }),
160    ///     prime1 INTEGER,
161    ///     prime2 INTEGER,
162    ///     exponent1 INTEGER,
163    ///     exponent2 INTEGER,
164    ///     coefficient INTEGER
165    /// }
166    /// ```
167    ///
168    /// This function takes:
169    /// * `privkey` - A `Vec<u8>` containing the key in the above format.
170    ///
171    /// On failure, a `KcapiError` is returned.
172    pub fn setprivkey(&mut self, privkey: Vec<u8>) -> KcapiResult<()> {
173        unsafe {
174            let ret = kcapi_sys::kcapi_akcipher_setkey(
175                self.handle,
176                privkey.as_ptr(),
177                privkey.len() as u32,
178            );
179
180            if ret < 0 {
181                return Err(KcapiError {
182                    code: ret,
183                    message: format!(
184                        "Failed to set private key for algorithm '{}'",
185                        self.algorithm
186                    ),
187                });
188            }
189            self.modsize = ret.try_into().expect("Failed to convert i32 into usize");
190            self.privkey = privkey;
191        }
192
193        Ok(())
194    }
195
196    ///
197    /// ## Set the Public Key
198    ///
199    /// This function is used to set the public key for encryption and
200    /// verification operations.
201    ///
202    /// The public key must be a `Vec<u8>` in DER format as follows:
203    ///
204    /// ```none
205    /// SEQUENCE {
206    ///     n INTEGER ({ rsa_get_n }),
207    ///     e INTEGER ({ rsa_get_e })
208    /// }
209    /// ```
210    ///
211    /// This function takes:
212    /// * `pubkey` - A `Vec<u8>` containing the public key in the above format.
213    ///
214    /// On failure, a `KcapiError` is returned.
215    ///
216    pub fn setpubkey(&mut self, pubkey: Vec<u8>) -> KcapiResult<()> {
217        unsafe {
218            let ret = kcapi_sys::kcapi_akcipher_setpubkey(
219                self.handle,
220                pubkey.as_ptr(),
221                pubkey.len() as u32,
222            );
223            if ret < 0 {
224                return Err(KcapiError {
225                    code: ret,
226                    message: format!(
227                        "Failed to set public key for algorithm '{}'",
228                        self.algorithm
229                    ),
230                });
231            }
232            self.modsize = ret.try_into().expect("Failed to convert i32 into usize");
233            self.pubkey = pubkey;
234        }
235        Ok(())
236    }
237
238    ///
239    /// ## Perform Asymmetric Encryption
240    ///
241    /// This function encrypts data using a public key. It is necessary to
242    /// set the publickey prior to calling `encrypt()`.
243    ///
244    /// *Note:* Only `self.modsize` bytes of data can be encrypted at a time.
245    ///
246    /// This function takes:
247    /// * `pt` - A `Vec<u8>` containing the plaintext to be encrypted.
248    /// * `access` - kernel access type (`u32`)
249    ///     - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
250    ///     - `ACCESS_VMSPLICE` - vmsplice access
251    ///     - `ACCESS_SENDMSG` - sendmsg access
252    ///
253    /// On success, returns a `Vec<u8>` wih the encrypted ciphertext.
254    /// On failure, returns `KcapiError`
255    ///
256    pub fn encrypt(&self, pt: Vec<u8>, access: u32) -> KcapiResult<Vec<u8>> {
257        crate::akcipher::check_input(self, pt.clone())?;
258
259        let mut ct = vec![0u8; self.modsize];
260        unsafe {
261            let ret = kcapi_sys::kcapi_akcipher_encrypt(
262                self.handle,
263                pt.as_ptr(),
264                pt.len() as kcapi_sys::size_t,
265                ct.as_mut_ptr(),
266                ct.len() as kcapi_sys::size_t,
267                access as i32,
268            );
269            if ret < 0 {
270                return Err(KcapiError {
271                    code: ret.try_into().expect("failed to convert i64 into i32"),
272                    message: format!("Failed to encrypt for algorithm '{}'", self.algorithm),
273                });
274            }
275        }
276        Ok(ct)
277    }
278
279    ///
280    /// ## Perform Asymmetric Decryption
281    ///
282    /// This function decrypts data using a private key. It is necessary to
283    /// set the privatekey prior to calling `decrypt()`.
284    ///
285    /// *Note:* Only `self.modsize` bytes of data can be decrypted at a time.
286    ///
287    /// This function takes:
288    /// * `pt` - A `Vec<u8>` containing the ciphertext to be decrypted.
289    /// * `access` - kernel access type (`u32`)
290    ///     - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
291    ///     - `ACCESS_VMSPLICE` - vmsplice access
292    ///     - `ACCESS_SENDMSG` - sendmsg access
293    ///
294    /// On success, returns a `Vec<u8>` wih the decrypted plaintext.
295    /// On failure, returns `KcapiError`
296    ///
297    pub fn decrypt(&self, ct: Vec<u8>, access: u32) -> KcapiResult<Vec<u8>> {
298        crate::akcipher::check_input(self, ct.clone())?;
299
300        let mut pt = vec![0u8; self.modsize];
301        unsafe {
302            let ret = kcapi_sys::kcapi_akcipher_decrypt(
303                self.handle,
304                ct.as_ptr(),
305                ct.len() as kcapi_sys::size_t,
306                pt.as_mut_ptr(),
307                pt.len() as kcapi_sys::size_t,
308                access as ::std::os::raw::c_int,
309            );
310            if ret < 0 {
311                return Err(KcapiError {
312                    code: ret.try_into().expect("failed to convert i64 into i32"),
313                    message: format!("Failed to decrypt for algorithm '{}'", self.algorithm),
314                });
315            }
316        }
317        Ok(pt)
318    }
319
320    ///
321    /// ## Perform Signing
322    ///
323    /// This function signs data using a private key. It is necessary to
324    /// set the privatekey prior to calling `sign()`.
325    ///
326    /// This function takes:
327    /// * `message` - A `Vec<u8>` containing the message to be signed.
328    /// * `access` - kernel access type (`u32`)
329    ///     - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
330    ///     - `ACCESS_VMSPLICE` - vmsplice access
331    ///     - `ACCESS_SENDMSG` - sendmsg access
332    ///
333    /// On success, returns a `Vec<u8>` wih the signature.
334    /// On failure, returns `KcapiError`
335    ///
336    pub fn sign(&self, message: Vec<u8>, access: u32) -> KcapiResult<Vec<u8>> {
337        crate::akcipher::check_input(self, message.clone())?;
338
339        let mut sig = vec![0u8; self.modsize];
340        unsafe {
341            let ret = kcapi_sys::kcapi_akcipher_sign(
342                self.handle,
343                message.as_ptr(),
344                message.len() as kcapi_sys::size_t,
345                sig.as_mut_ptr(),
346                sig.len() as kcapi_sys::size_t,
347                access as ::std::os::raw::c_int,
348            );
349            if ret < 0 {
350                return Err(KcapiError {
351                    code: ret.try_into().expect("failed to convert i64 into i32"),
352                    message: format!("Failed to sign for algorithm '{}'", self.algorithm),
353                });
354            }
355        }
356        Ok(sig)
357    }
358
359    ///
360    /// ## Perform Signature Verification
361    ///
362    /// This function verifys data using a private key. It is necessary to
363    /// set the privatekey prior to calling `verify()`.
364    ///
365    /// This function takes:
366    /// * `message` - A `Vec<u8>` containing the message to be verified.
367    /// * `sig` - A `Vec<u8>` containing the signature to be verified.
368    /// * `access` - kernel access type (`u32`)
369    ///     - `ACCESS_HEURISTIC` - internal heuristic for fastest kernel access
370    ///     - `ACCESS_VMSPLICE` - vmsplice access
371    ///     - `ACCESS_SENDMSG` - sendmsg access
372    ///
373    /// On failure to verify the signature, returns `KcapiError` with the `code`
374    /// field set to `EBADMSG`.
375    ///
376    pub fn verify(&self, message: Vec<u8>, sig: Vec<u8>, access: u32) -> KcapiResult<()> {
377        crate::akcipher::check_input(self, sig.clone())?;
378
379        let mut inp = Vec::new();
380        inp.extend(sig.iter().copied());
381        inp.extend(message.iter().copied());
382
383        let mut out = vec![0u8; self.modsize];
384        unsafe {
385            let ret = kcapi_sys::kcapi_akcipher_verify(
386                self.handle,
387                inp.as_ptr(),
388                inp.len() as kcapi_sys::size_t,
389                out.as_mut_ptr(),
390                out.len() as kcapi_sys::size_t,
391                access as ::std::os::raw::c_int,
392            );
393            if ret < 0 {
394                return Err(KcapiError {
395                    code: -libc::EBADMSG,
396                    message: format!(
397                        "Failed to verify signature for algorithm '{}'",
398                        self.algorithm
399                    ),
400                });
401            }
402        }
403        Ok(())
404    }
405}
406
407impl Drop for KcapiAKCipher {
408    fn drop(&mut self) {
409        unsafe {
410            kcapi_sys::kcapi_akcipher_destroy(self.handle);
411        }
412    }
413}
414
415impl VMSplice for KcapiAKCipher {
416    ///
417    /// ## Get Maximum buffer size of VMSPLICE Access
418    ///
419    /// This function returns the maximum number of bytes that can be handled
420    /// by a VMSPLICE call to the kernel.
421    ///
422    fn get_max_splicesize(&self) -> usize {
423        let size: usize;
424        unsafe {
425            size = kcapi_sys::kcapi_get_maxsplicesize(self.handle) as usize;
426        }
427        size
428    }
429
430    ///
431    /// ## Set Maximum Buffer Size for VMSPLICE Access
432    ///
433    /// When using vmsplice/splice to avoid copying of data into the kernel, the
434    /// kernel enforces a maximum number of bytes which can be spliced. If larger
435    /// data is to be processed, sendmsg will be used.
436    ///
437    /// Using this call, the buffer size can be increased.
438    ///
439    /// *NOTE:* Splice uses a pipe pair. Therefore, the maximum number of bytes
440    /// that can be stored with the pipe governs the maximum data size to be
441    /// spliced. Increasing the pipe buffer size is only allowed up to the maximum
442    /// specified with `/proc/sys/fs/pipe-max-size`.
443    ///
444    /// This function takes:
445    /// `size` - A `usize` denoting the size of the vmsplice buffer.
446    ///
447    /// On failure a `KcapiResult` is returned.
448    ///
449    fn set_max_splicesize(&self, size: usize) -> KcapiResult<()> {
450        unsafe {
451            let ret =
452                kcapi_sys::kcapi_set_maxsplicesize(self.handle, size as ::std::os::raw::c_uint);
453
454            if ret < 0 {
455                return Err(KcapiError {
456                    code: ret,
457                    message: format!(
458                        "Unable to set max splice size {} for algorithm {}",
459                        size, self.algorithm,
460                    ),
461                });
462            }
463        }
464        Ok(())
465    }
466}
467
468fn check_input(handle: &KcapiAKCipher, inp: Vec<u8>) -> KcapiResult<()> {
469    if handle.privkey.is_empty() && handle.pubkey.is_empty() {
470        return Err(KcapiError {
471            code: -libc::EINVAL,
472            message: format!(
473                "Required asymmetric key is not set for algorithm '{}'",
474                handle.algorithm
475            ),
476        });
477    }
478    if inp.len() > handle.modsize {
479        return Err(KcapiError {
480            code: -libc::EINVAL,
481            message: format!(
482                "Input to asymmetric cipher is larger than modulus size for algorithm {}",
483                handle.algorithm
484            ),
485        });
486    }
487    Ok(())
488}
489
490///
491/// ## Convenience Function to Perform Asymmetric Encryption
492///
493/// This function encrypts data using a public key. The key provided
494/// for the encryption operation should be DER encoded in the following
495/// format:
496///
497/// ```none
498/// SEQUENCE {
499///     n INTEGER ({ rsa_get_n }),
500///     e INTEGER ({ rsa_get_e })
501/// }
502/// ```
503///
504/// *Note:* Only `self.modsize` bytes of data can be encrypted at a time.
505///
506/// This function takes:
507/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
508/// * `key` - A `Vec<u8>` with the public key.
509/// * `pt` - A `Vec<u8>` containing the plaintext to be encrypted.
510///
511/// On success, returns a `Vec<u8>` wih the encrypted ciphertext.
512/// On failure, returns `KcapiError`
513///
514pub fn encrypt(alg: &str, key: Vec<u8>, pt: Vec<u8>) -> KcapiResult<Vec<u8>> {
515    let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
516    handle.setpubkey(key)?;
517    let ct = handle.encrypt(pt, ACCESS_HEURISTIC)?;
518    Ok(ct)
519}
520
521///
522/// ## Convenience Function to Perform Asymmetric Decryption
523///
524/// This function decrypts data using a private key.
525/// The key must be a `Vec<u8>` in DER format as follows:
526///
527/// ```none
528/// SEQUENCE {
529///     version INTEGER,
530///     n INTEGER ({ rsa_get_n }),
531///     e INTEGER ({ rsa_get_e }),
532///     d INTEGER ({ rsa_get_d }),
533///     prime1 INTEGER,
534///     prime2 INTEGER,
535///     exponent1 INTEGER,
536///     exponent2 INTEGER,
537///     coefficient INTEGER
538/// }
539/// ```
540///
541/// *Note:* Only `self.modsize` bytes of data can be decrypted at a time.
542///
543/// This function takes:
544/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
545/// * `key` - A `Vec<u8>` with the private key.
546/// * `ct` - A `Vec<u8>` containing the ciphertext to be decrypted.
547///
548/// On success, returns a `Vec<u8>` wih the decrypted plaintext.
549/// On failure, returns `KcapiError`
550///
551pub fn decrypt(alg: &str, key: Vec<u8>, ct: Vec<u8>) -> KcapiResult<Vec<u8>> {
552    let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
553    handle.setprivkey(key)?;
554    let pt = handle.decrypt(ct, ACCESS_HEURISTIC)?;
555    Ok(pt)
556}
557
558///
559/// ## Convenience Function to Perform Signing
560///
561/// This function signs data using a private key.
562/// The key must be a `Vec<u8>` in DER format as follows:
563///
564/// ```none
565/// SEQUENCE {
566///     version INTEGER,
567///     n INTEGER ({ rsa_get_n }),
568///     e INTEGER ({ rsa_get_e }),
569///     d INTEGER ({ rsa_get_d }),
570///     prime1 INTEGER,
571///     prime2 INTEGER,
572///     exponent1 INTEGER,
573///     exponent2 INTEGER,
574///     coefficient INTEGER
575/// }
576/// ```
577///
578/// This function takes:
579/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
580/// * `key` - A `Vec<u8>` with the private key.
581/// * `message` - A `Vec<u8>` containing the message to be signed.
582///
583/// On success, returns a `Vec<u8>` wih the signature.
584/// On failure, returns `KcapiError`
585///
586pub fn sign(alg: &str, key: Vec<u8>, message: Vec<u8>) -> KcapiResult<Vec<u8>> {
587    let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
588    handle.setprivkey(key)?;
589    let sig = handle.sign(message, ACCESS_HEURISTIC)?;
590    Ok(sig)
591}
592
593///
594/// ## Perform Signature Verification
595///
596/// This function verifys data using a private key. The key provided
597/// for the encryption operation should be DER encoded in the following
598/// format:
599///
600/// ```none
601/// SEQUENCE {
602///     n INTEGER ({ rsa_get_n }),
603///     e INTEGER ({ rsa_get_e })
604/// }
605/// ```
606///
607/// This function takes:
608/// * `alg` - A `&str` representation of an akcipher algorithm from `/proc/crypto`.
609/// * `key` - A `Vec<u8>` with the public key.
610/// * `message` - A `Vec<u8>` containing the message to be verified.
611/// * `sig` - A `Vec<u8>` containing the signature to be verified.
612///
613/// On failure to verify the signature, returns `KcapiError` with the `code`
614/// field set to `EBADMSG`.
615///
616pub fn verify(alg: &str, key: Vec<u8>, message: Vec<u8>, sig: Vec<u8>) -> KcapiResult<()> {
617    let mut handle = KcapiAKCipher::new(alg, !INIT_AIO)?;
618    handle.setpubkey(key)?;
619    handle.verify(message, sig, ACCESS_HEURISTIC)?;
620    Ok(())
621}