noxtls_psa/ffi.rs
1// Copyright (c) 2019-2026, Argenox Technologies LLC
2// All rights reserved.
3//
4// SPDX-License-Identifier: GPL-2.0-only OR LicenseRef-Argenox-Commercial-License
5//
6// This file is part of the NoxTLS Library.
7//
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU General Public License as published by the
10// Free Software Foundation; version 2 of the License.
11//
12// Alternatively, this file may be used under the terms of a commercial
13// license from Argenox Technologies LLC.
14//
15// See `noxtls/LICENSE` and `noxtls/LICENSE.md` in this repository for full details.
16// CONTACT: info@argenox.com
17
18#[cfg(feature = "alloc")]
19use alloc::vec::Vec;
20use noxtls_core::{Error, Result};
21
22use crate::provider::{
23 AeadEncryptRequest, AeadEncryptResponse, KeyDecryptRequest, KeyDeriveRequest, KeySignRequest,
24 PsaCryptoBackend,
25};
26
27/// Implements the PSA backend trait for FFI-backed targets.
28#[derive(Clone, Debug, Default)]
29pub struct FfiPsaBackend;
30
31impl FfiPsaBackend {
32 /// Creates a new FFI-backed backend adapter.
33 ///
34 /// # Arguments
35 ///
36 /// * `()` - This constructor has no parameters.
37 ///
38 /// # Returns
39 ///
40 /// A default [`FfiPsaBackend`] instance.
41 pub fn new() -> Self {
42 Self
43 }
44
45 /// Returns whether this build includes direct PSA FFI shims.
46 ///
47 /// # Arguments
48 ///
49 /// * `self` - Backend instance for capability checks.
50 ///
51 /// # Returns
52 ///
53 /// `true` when the `mbedtls-psa-ffi` feature is enabled, otherwise `false`.
54 pub fn has_ffi_shims(&self) -> bool {
55 cfg!(feature = "mbedtls-psa-ffi")
56 }
57}
58
59impl PsaCryptoBackend for FfiPsaBackend {
60 /// Signs input digest bytes using a key handle and algorithm selected in request.
61 ///
62 /// # Arguments
63 ///
64 /// * `self` - Backend instance receiving sign request dispatch.
65 /// * `request` - Sign request carrying key handle, algorithm, and digest bytes.
66 ///
67 /// # Returns
68 ///
69 /// Signature bytes if supported by this backend implementation.
70 ///
71 /// # Errors
72 ///
73 /// Returns [`Error::UnsupportedFeature`] until concrete FFI hooks are linked.
74 fn sign(&self, request: &KeySignRequest<'_>) -> Result<Vec<u8>> {
75 let _ = request;
76 Err(Error::UnsupportedFeature(
77 "psa ffi sign unavailable without linked backend",
78 ))
79 }
80
81 /// Decrypts ciphertext bytes using a key handle and requested mechanism.
82 ///
83 /// # Arguments
84 ///
85 /// * `self` - Backend instance receiving decrypt request dispatch.
86 /// * `request` - Decrypt request containing handle, algorithm, and ciphertext.
87 ///
88 /// # Returns
89 ///
90 /// Decrypted plaintext bytes if backend supports this operation.
91 ///
92 /// # Errors
93 ///
94 /// Returns [`Error::UnsupportedFeature`] until concrete FFI hooks are linked.
95 fn decrypt(&self, request: &KeyDecryptRequest<'_>) -> Result<Vec<u8>> {
96 let _ = request;
97 Err(Error::UnsupportedFeature(
98 "psa ffi decrypt unavailable without linked backend",
99 ))
100 }
101
102 /// Derives shared-secret bytes for a key handle and peer public key.
103 ///
104 /// # Arguments
105 ///
106 /// * `self` - Backend instance receiving derive request dispatch.
107 /// * `request` - Derive request with handle, algorithm, and peer public bytes.
108 ///
109 /// # Returns
110 ///
111 /// Shared secret bytes derived by the configured algorithm.
112 ///
113 /// # Errors
114 ///
115 /// Returns [`Error::UnsupportedFeature`] until concrete FFI hooks are linked.
116 fn derive(&self, request: &KeyDeriveRequest<'_>) -> Result<Vec<u8>> {
117 let _ = request;
118 Err(Error::UnsupportedFeature(
119 "psa ffi derive unavailable without linked backend",
120 ))
121 }
122
123 /// Fills the output buffer with random bytes from PSA entropy source.
124 ///
125 /// # Arguments
126 ///
127 /// * `self` - Backend instance receiving random generation request.
128 /// * `out` - Mutable byte slice to fill with random output.
129 ///
130 /// # Returns
131 ///
132 /// `Ok(())` when random bytes were produced.
133 ///
134 /// # Errors
135 ///
136 /// Returns [`Error::UnsupportedFeature`] until concrete FFI hooks are linked.
137 fn random(&self, out: &mut [u8]) -> Result<()> {
138 let _ = out;
139 Err(Error::UnsupportedFeature(
140 "psa ffi random unavailable without linked backend",
141 ))
142 }
143
144 /// Computes SHA-256 digest for the input payload.
145 ///
146 /// # Arguments
147 ///
148 /// * `self` - Backend instance receiving hash request dispatch.
149 /// * `input` - Bytes to hash with SHA-256.
150 ///
151 /// # Returns
152 ///
153 /// A 32-byte SHA-256 digest.
154 ///
155 /// # Errors
156 ///
157 /// Returns [`Error::UnsupportedFeature`] until concrete FFI hooks are linked.
158 fn sha256(&self, input: &[u8]) -> Result<[u8; 32]> {
159 let _ = input;
160 Err(Error::UnsupportedFeature(
161 "psa ffi sha256 unavailable without linked backend",
162 ))
163 }
164
165 /// Encrypts plaintext bytes with AES-GCM and returns ciphertext plus tag.
166 ///
167 /// # Arguments
168 ///
169 /// * `self` - Backend instance receiving AEAD encryption request.
170 /// * `request` - AES-GCM request with key, nonce, AAD, and plaintext.
171 ///
172 /// # Returns
173 ///
174 /// Ciphertext and 16-byte tag on successful encryption.
175 ///
176 /// # Errors
177 ///
178 /// Returns [`Error::UnsupportedFeature`] until concrete FFI hooks are linked.
179 fn aes_gcm_encrypt(&self, request: &AeadEncryptRequest<'_>) -> Result<AeadEncryptResponse> {
180 let _ = request;
181 Err(Error::UnsupportedFeature(
182 "psa ffi aes-gcm unavailable without linked backend",
183 ))
184 }
185}