kipuka_otp/lib.rs
1//! One-Time Password generation, validation, and lifecycle for EST enrollment.
2//!
3//! Provides OTP creation, cryptographic storage, and consumption for EST
4//! enrollment authentication per RHELBU-3536 R7-R12:
5//! - R7: Minimum 128-bit entropy for generated tokens
6//! - R8: Timing-safe comparison during validation
7//! - R9: Single-use and multi-use token support
8//! - R10: Configurable expiration and max-use limits
9//! - R11: Tokens stored as SHA-256 hashes (never plaintext)
10//! - R12: Periodic cleanup of expired tokens
11
12pub mod generate;
13pub mod store;
14pub mod validate;
15
16pub use generate::{OtpGenerator, OtpGeneratorConfig, OtpMetadata};
17pub use store::{DbOtpStore, InMemoryOtpStore, OtpRecord, OtpStore as OtpStoreTrait};
18pub use validate::{OtpValidator, ValidationResult};
19
20use std::sync::Arc;
21
22/// Errors produced by OTP operations.
23#[derive(Debug, thiserror::Error)]
24pub enum OtpError {
25 /// The supplied OTP token was not found in the store.
26 #[error("OTP token not found")]
27 NotFound,
28
29 /// The OTP has expired.
30 #[error("OTP has expired (expired at {expired_at})")]
31 Expired {
32 /// ISO-8601 expiration timestamp.
33 expired_at: String,
34 },
35
36 /// The OTP has exceeded its maximum usage count.
37 #[error("OTP usage limit exceeded ({max_uses} uses allowed)")]
38 UsageLimitExceeded {
39 /// Configured maximum uses.
40 max_uses: u32,
41 },
42
43 /// The OTP has been explicitly revoked by an administrator.
44 #[error("OTP has been revoked")]
45 Revoked,
46
47 /// Cryptographic or RNG error during token generation.
48 #[error("token generation failed: {0}")]
49 GenerationError(String),
50
51 /// Storage backend error.
52 #[error("storage error: {0}")]
53 StorageError(String),
54}
55
56/// Convenience alias for OTP operation results.
57pub type OtpResult<T> = Result<T, OtpError>;
58
59/// Placeholder OTP storage and validation engine.
60///
61/// Preserves backward compatibility with the main binary's initialization
62/// until the full OTP subsystem is wired in.
63pub struct OtpStore {
64 _private: (),
65}
66
67impl OtpStore {
68 /// Create a placeholder OTP store (backend integration pending).
69 pub fn placeholder() -> Arc<Self> {
70 Arc::new(Self { _private: () })
71 }
72}