Skip to main content

fe11_verify_engine_api/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2//! C ABI for the optional Fe11 verification engine, independent of PKCS#11 tables.
3//!
4//! All requests are synchronous: no input pointer is retained after return. The caller
5//! pins the component image before invoking anything other than GetInterface.
6//! Inputs stay initialized, immutable and readable for their full lengths until
7//! return; output slots are aligned, exclusively writable and disjoint from inputs.
8//! Integer representations accept all bit patterns and
9//! are validated by the callee. The calling thread must not reenter this engine
10//! during a request. Calls from different threads are independent. No Rust
11//! allocation crosses the ownership boundary: an owned byte view is released by
12//! the originating component. The caller never reconstructs or frees that owner.
13#![no_std]
14use core::ffi::c_void;
15
16// This table exposes public verification services. Version and exact table
17// size are checked before either side consumes any service fields.
18/// Version of the public component ABI.
19pub const ABI_VERSION: u32 = 2;
20/// NUL-terminated exported discovery symbol.
21pub const ENTRY_POINT: &[u8] = b"Fe11_VerifyEngine_GetInterface\0";
22
23/// Service completion and failure codes.
24pub mod status {
25    /// The service completed; a verification verdict is reported separately.
26    pub const OK: u32 = 0;
27    /// The request representation or parameter combination was refused.
28    pub const INVALID_REQUEST: u32 = 1;
29    /// A required implementation or exact preparation is unavailable.
30    pub const UNAVAILABLE: u32 = 2;
31    /// The engine failed while executing the request.
32    pub const ENGINE_FAILURE: u32 = 3;
33    /// A required allocation failed.
34    pub const ALLOCATION_FAILURE: u32 = 4;
35}
36/// Public-key representation codes.
37pub mod key_format {
38    /// Complete DER-encoded SubjectPublicKeyInfo.
39    pub const SPKI_DER: u32 = 1;
40    /// Algorithm-specific raw public-key bytes.
41    pub const RAW_PUBLIC: u32 = 2;
42}
43/// Signature verification scheme codes.
44pub mod scheme {
45    /// RSA PKCS#1 v1.5 signature verification with an explicit digest.
46    pub const RSA_PKCS1: u32 = 1;
47    /// RSA-PSS verification with explicit digest, MGF1 digest and salt length.
48    pub const RSA_PSS: u32 = 2;
49    /// Digest-based signature scheme; the supplied engine accepts EC public keys.
50    pub const DIGEST_SIGNATURE: u32 = 3;
51    /// Pure Ed25519 or Ed448 verification.
52    pub const PURE_EDDSA: u32 = 4;
53    /// ML-DSA or SLH-DSA verification with explicit message framing.
54    pub const PQC: u32 = 5;
55    /// Explicit RFC8032 instance, context and original-message input.
56    pub const EDDSA: u32 = 6;
57}
58/// Instance codes for scheme::EDDSA in VerificationRequest::message_encoding.
59/// The ABI layout is unchanged; older engines may reject the added scheme.
60pub mod eddsa_instance {
61    /// Pure Ed25519 with an empty context.
62    pub const ED25519: u32 = 1;
63    /// Ed25519ctx with the supplied context.
64    pub const ED25519_CONTEXT: u32 = 2;
65    /// Ed25519ph with original-message input and the supplied context.
66    pub const ED25519_PREHASH: u32 = 3;
67    /// Ed448 with the supplied context.
68    pub const ED448: u32 = 4;
69    /// Ed448ph with original-message input and the supplied context.
70    pub const ED448_PREHASH: u32 = 5;
71}
72/// Borrowed bytes; null is accepted only with a zero length. Identifier fields
73/// contain UTF-8 names without NUL; ordinary data fields are unrestricted bytes.
74#[repr(C)]
75#[derive(Clone, Copy)]
76pub struct Bytes {
77    /// Start of readable input storage; NULL is valid only when length is zero.
78    pub pointer: *const u8,
79    /// Number of readable bytes starting at pointer.
80    pub length: usize,
81}
82impl Bytes {
83    /// Empty descriptor with a null pointer and zero length.
84    pub const EMPTY: Self = Self {
85        pointer: core::ptr::null(),
86        length: 0,
87    };
88    /// Borrow a slice as a descriptor; the caller preserves its storage through use.
89    pub fn from_slice(bytes: &[u8]) -> Self {
90        Self {
91            pointer: bytes.as_ptr(),
92            length: bytes.len(),
93        }
94    }
95}
96/// Engine-owned allocation. Only release(owner), exactly once, may destroy it.
97/// The view stays readable until release. None of these fields may be modified
98/// to construct a different allocation; even a zero-length owned view is released.
99#[repr(C)]
100#[derive(Clone, Copy)]
101pub struct OwnedBytes {
102    /// Opaque allocation token returned by the engine; release once through that engine.
103    pub owner: *mut c_void,
104    /// Readable result view whose lifetime ends when owner is released.
105    pub bytes: Bytes,
106}
107impl OwnedBytes {
108    /// Empty descriptor with a null pointer or owner and zero length.
109    pub const EMPTY: Self = Self {
110        owner: core::ptr::null_mut(),
111        bytes: Bytes::EMPTY,
112    };
113}
114/// Versions reported by the selected component and its private crypto library.
115#[repr(C)]
116#[derive(Clone, Copy)]
117pub struct Information {
118    /// Component ABI version; compare with ABI_VERSION.
119    pub abi_version: u32,
120    /// Size in bytes of this Information representation.
121    pub structure_size: u32,
122    /// Component package version as major, minor and patch numbers.
123    pub implementation_version: [u32; 3],
124    /// Numeric version of the component's private OpenSSL library.
125    pub openssl_version: u64,
126}
127/// Implementations required for a future verification, without a key. Names are
128/// UTF-8 without NUL; digest names may be empty when not needed. Success reports
129/// that each implementation can be fetched in the engine's private context. It
130/// does not establish that their combination or a future key can be initialized;
131/// explicit public-key verification uses the exact-key Probe to establish its
132/// own operation requirements. No private possession-proof policy is provided.
133#[repr(C)]
134#[derive(Clone, Copy)]
135pub struct VerificationAlgorithms {
136    /// UTF-8 key-management algorithm name without NUL bytes.
137    pub key_algorithm: Bytes,
138    /// UTF-8 signature implementation name without NUL bytes.
139    pub signature_algorithm: Bytes,
140    /// UTF-8 digest name, or empty when the requested scheme uses none.
141    pub digest: Bytes,
142    /// UTF-8 MGF digest name, or empty when the requested scheme uses none.
143    pub mgf_digest: Bytes,
144}
145/// Exact public verification parameters. Empty digest names mean no digest;
146/// unused fields must be zero/empty. PQC encoding is 1 for engine framing and
147/// 0 when Fe11 already supplied its exact FIPS frame. Context is not applied twice.
148/// For scheme::EDDSA, message_encoding is an eddsa_instance code, digest/MGF
149/// names and salt must be empty/zero, and input is the original message.
150#[repr(C)]
151#[derive(Clone, Copy)]
152pub struct VerificationRequest {
153    /// UTF-8 public-key algorithm name without NUL bytes.
154    pub algorithm: Bytes,
155    /// Public-key representation selected from key_format.
156    pub key_format: u32,
157    /// Complete public-key encoding in the selected format, borrowed through the call.
158    pub key: Bytes,
159    /// Signature operation selected from scheme.
160    pub scheme: u32,
161    /// Explicit message-digest name; empty for a scheme without a separate digest.
162    pub digest: Bytes,
163    /// RSA-PSS MGF1 digest name; empty for other schemes.
164    pub mgf_digest: Bytes,
165    /// Exact RSA-PSS salt length in bytes; zero for other schemes.
166    pub salt_length: u64,
167    /// EdDSA or PQC domain-separation context; empty when unused.
168    pub context: Bytes,
169    /// For EDDSA, an eddsa_instance code; for PQC, 1 for engine framing or 0 for an already framed message; zero otherwise.
170    pub message_encoding: u32,
171}
172/// Parameters for a synchronous whole-message digest request.
173#[repr(C)]
174#[derive(Clone, Copy)]
175pub struct DigestRequest {
176    /// UTF-8 digest implementation name without NUL bytes.
177    pub algorithm: Bytes,
178    /// Requested digest length in bytes; exact method width for a fixed-size hash.
179    pub output_length: usize,
180    /// Zero selects a fixed-size hash; one selects extendable output.
181    pub xof: u32,
182    /// Complete input message borrowed through this synchronous request.
183    pub message: Bytes,
184}
185/// Read component/engine versions into the caller's exact-sized output slot.
186/// This may initialize the private engine; the image must already be pinned.
187pub type ReadInformation =
188    unsafe extern "C" fn(output: *mut Information, output_size: usize) -> u32;
189
190/// Import the public key and prepare the exact parameters without verification.
191/// OK establishes preparation availability, not validity of a future signature.
192pub type Probe =
193    unsafe extern "C" fn(request: *const VerificationRequest, request_size: usize) -> u32;
194
195/// Check implementation availability without generating/importing a key or
196/// performing a PKCS#11 operation. See VerificationAlgorithms for the limited
197/// meaning of success; missing implementations return UNAVAILABLE.
198pub type CheckVerificationAlgorithms =
199    unsafe extern "C" fn(request: *const VerificationAlgorithms, request_size: usize) -> u32;
200
201/// Verify one message/signature pair. OK with verified=0 is a signature mismatch;
202/// engine/parameter failures have a non-OK status and never claim a mismatch.
203pub type Verify = unsafe extern "C" fn(
204    request: *const VerificationRequest,
205    request_size: usize,
206    message: Bytes,
207    signature: Bytes,
208    verified: *mut u32,
209) -> u32;
210
211/// Hash one whole message. On success the caller copies the result then releases
212/// its owner; no output allocation belongs to the caller's allocator.
213pub type Digest = unsafe extern "C" fn(
214    request: *const DigestRequest,
215    request_size: usize,
216    output: *mut OwnedBytes,
217) -> u32;
218
219/// Consume an unmodified owner returned by this image, exactly once. Null is a
220/// no-op. Every borrowed view of the allocation becomes invalid after this call.
221pub type Release = unsafe extern "C" fn(owner: *mut c_void);
222
223/// Function pointers use the C calling convention on every supported target.
224/// Every request receives its structure size; mismatched sizes are refused before
225/// dereferencing fields. Valid output slots are empty/zero on non-OK return;
226/// invalid output size/alignment is rejected without accessing that storage. Probe
227/// prepares the exact operation without signing or issuing any PKCS#11 call.
228#[repr(C)]
229#[derive(Clone, Copy)]
230pub struct Interface {
231    /// Size in bytes of this exact Interface representation.
232    pub structure_size: u32,
233    /// Version governing the layout and service contracts.
234    pub abi_version: u32,
235    /// Optional version-information service; Fe11 requires it when selecting an engine.
236    pub information: Option<ReadInformation>,
237    /// Optional exact-key verification preparation service.
238    pub probe: Option<Probe>,
239    /// Optional keyless implementation-availability service.
240    pub verification_algorithms: Option<CheckVerificationAlgorithms>,
241    /// Optional message/signature verification service; requires the preparation service.
242    pub verify: Option<Verify>,
243    /// Optional whole-message hashing service; returned allocations require release.
244    pub digest: Option<Digest>,
245    /// Optional originating-allocator release service for OwnedBytes results.
246    pub release: Option<Release>,
247}
248/// GetInterface performs no OpenSSL initialization. A successful call copies the
249/// exact requested ABI table into the caller's storage; it never returns a table
250/// pointer with an inferred suffix length. Version/size mismatch writes nothing.
251pub type GetInterface =
252    unsafe extern "C" fn(requested_version: u32, output: *mut Interface, output_size: usize) -> u32;