Skip to main content

kipuka_coap/
lib.rs

1//! EST over CoAP (RFC 9148) transport for constrained devices.
2//!
3//! This crate implements the CoAP transport binding for Enrollment over Secure
4//! Transport, enabling EST operations on constrained IoT devices that cannot
5//! use HTTP/TLS.
6//!
7//! # Protocol Mapping
8//!
9//! RFC 9148 maps EST operations to CoAP as follows:
10//! - HTTPS transport is replaced by CoAP over DTLS ("coaps")
11//! - EST URI paths use abbreviated names (e.g., `/sen` for `/simpleenroll`)
12//! - HTTP Content-Type headers map to CoAP Content-Format option IDs
13//! - Large payloads (PQC certificates can exceed 7KB) use RFC 7959 block-wise transfer
14//!
15//! # Modules
16//!
17//! - [`server`]: CoAP message parsing, encoding, and EST-coaps URI routing
18//! - [`dtls`]: DTLS session management abstraction for CoAP security
19//! - [`block`]: RFC 7959 block-wise transfer for large EST payloads
20//! - [`content_format`]: CoAP content-format IDs for EST media types (RFC 9148 §5.4)
21
22pub mod block;
23pub mod content_format;
24pub mod dtls;
25pub mod server;
26
27pub use server::{AuditInfo, CoapDtlsServer, EstHandler, EstResponse};
28
29use thiserror::Error;
30
31/// Errors arising from CoAP/EST-coaps protocol handling.
32#[derive(Debug, Error, Clone)]
33pub enum CoapError {
34    /// Malformed CoAP message (header, token, or option encoding).
35    #[error("Invalid CoAP message: {0}")]
36    InvalidMessage(String),
37
38    /// Unrecognized or unsupported CoAP method code.
39    #[error("Unsupported CoAP method: {0}")]
40    UnsupportedMethod(String),
41
42    /// Unrecognized CoAP Content-Format option value.
43    ///
44    /// RFC 9148 §5.4 defines the content-format IDs that EST-coaps supports.
45    #[error("Unsupported Content-Format: {0}")]
46    UnsupportedContentFormat(u16),
47
48    /// Block-wise transfer failure per RFC 7959.
49    #[error("Block transfer error: {0}")]
50    BlockTransferError(String),
51
52    /// DTLS session establishment or resumption failure.
53    ///
54    /// RFC 9148 §5 requires DTLS to secure all EST-coaps exchanges.
55    #[error("DTLS error: {0}")]
56    DtlsError(String),
57
58    /// Payload exceeds the configured maximum size.
59    ///
60    /// Even with block-wise transfer, reassembled payloads are bounded to
61    /// prevent resource exhaustion on constrained devices.
62    #[error("Payload too large: {size} bytes exceeds maximum {max} bytes")]
63    PayloadTooLarge {
64        /// Actual payload size in bytes.
65        size: usize,
66        /// Configured maximum payload size in bytes.
67        max: usize,
68    },
69
70    /// No CoAP resource matches the requested URI path.
71    #[error("Resource not found: {0}")]
72    ResourceNotFound(String),
73
74    /// Client authentication required but not provided (4.01).
75    ///
76    /// Returned when an EST operation requires mTLS client certificate
77    /// authentication but no certificate was presented during the DTLS
78    /// handshake.
79    #[error("Unauthorized: {0}")]
80    Unauthorized(String),
81
82    /// Authenticated client is not authorized for the request (4.03).
83    ///
84    /// The peer authenticated successfully but the request is denied by an
85    /// access-control policy — e.g. the EST enrollment-authorization check
86    /// (NIAP CA PP FDP_ACF.1): the CSR names an identity the requester is not
87    /// permitted to enroll.  Distinct from [`Unauthorized`](Self::Unauthorized),
88    /// which means authentication itself is missing.
89    #[error("Forbidden: {0}")]
90    Forbidden(String),
91
92    /// Internal server error (catch-all).
93    #[error("Internal error: {0}")]
94    Internal(String),
95}
96
97/// Result type for CoAP operations.
98pub type CoapResult<T> = Result<T, CoapError>;