FreeBSD /dev/crypto: Session Lifetimes, AEAD, and Provider Policy
Operate FreeBSD's /dev/crypto ioctl API with explicit session cleanup, AEAD buffer contracts, provider policy, and a verified CPU-accelerated AES-NI software path.
FreeBSD’s /dev/crypto is an ioctl interface for user-mode programs that want cryptographic transforms through the kernel’s crypto framework. It is not an encrypted-filesystem control, a hardware security module, or a promise that a particular library will use a hardware engine. A program must open the device, create a session for the requested algorithms and keys, submit operations, and clean up that session. Which providers can serve the request depends on the system’s driver set and software-provider policy.
This guide focuses on the userland session API documented by FreeBSD 15.0-RELEASE. The manual-page contracts and aesni(4) setup discussed here were checked against that release’s documentation; confirm the manual for the exact release and kernel configuration you operate. The article does not claim that a given application, cipher suite, or crypto library will select /dev/crypto automatically.
Understand the session boundary
The crypto(4) manual describes a short lifecycle:
- Open
/dev/cryptoand retain the file descriptor for the intended work. - Create one or more sessions with
CIOCGSESSIONorCIOCGSESSION2. - Submit synchronous requests with
CIOCCRYPTorCIOCCRYPTAEAD. - Optionally destroy an individual session with
CIOCFSESSIONwhen it is no longer needed. - Close the device descriptor; FreeBSD closes any remaining sessions associated with it.
A session is a persistent object for the chosen privacy algorithm, integrity algorithm, and keys. Its returned session identifier is supplied with later operation requests. Treat that identifier as scoped to the file descriptor that created it, and keep session ownership explicit in the application: a worker that closes the descriptor must not leave another thread assuming its session remains valid. Reuse a session only where the algorithm, key, and concurrency model match the operation. The manual documents the API behavior, but it does not provide an application-level synchronization policy for a program sharing sessions across threads.
CIOCGSESSION2 adds a crid field that can request a particular crypto device or a class of devices, as well as explicit IV/nonce and MAC/tag lengths. That is a dispatch request, not proof of successful acceleration. Supported algorithms and combinations depend on installed providers, and FreeBSD’s manual warns that hardware can support individual operations without supporting a particular fused cipher-and-integrity combination. If you require a specific provider or fused operation, request it explicitly where supported and fail closed or choose a reviewed fallback; do not silently report “hardware encrypted” merely because session creation succeeded.
Apply provider policy deliberately
In the FreeBSD releng/15.0 source, the allow-soft setting is backed by crypto_devallowsoft and exposed as kern.crypto.allow_soft; the older kern.cryptodevallowsoft name is a compatibility alias when COMPAT_FREEBSD12 is enabled. Its default is zero. In that state, /dev/crypto’s provider check rejects software-only provider selections (with EINVAL) and requires a hardware-capable match. This is a /dev/crypto userland-session policy, not a claim that every kernel crypto consumer is restricted the same way. Inspect the sysctl name available on the target kernel and the loaded or built-in driver set before diagnosing a request failure. A restrictive setting can be intentional; changing it to make a workload work may permit a software provider that violates the operator’s expected boundary.
For the x86 AES/SHA path, FreeBSD 15.0’s aesni implementation registers the driver with CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC | CRYPTOCAP_F_ACCEL_SOFTWARE, and its session probe reports CRYPTODEV_PROBE_ACCEL_SOFTWARE. It uses CPU instruction capabilities, but OpenCrypto classifies it as accelerated software, not as a separate hardware cryptographic coprocessor. Consequently, a /dev/crypto request subject to an allow-soft value of zero cannot rely on aesni as a hardware-only provider. The aesni(4) manual documents a kernel configuration with device crypto, device cryptodev, and device aesni; alternatively, it documents loading the module at boot with aesni_load="YES". The driver attaches only on systems exposing the required CPU instruction capability, and it can support AES or SHA when a system has only one of those instruction sets. Verify the target CPU capability and boot/driver messages rather than assuming that the kernel option guarantees attachment.
This describes the provider path, not end-to-end application acceleration. The application must use the cryptodev interface or a library/provider that explicitly supports it. An OpenSSL-based application, for example, may instead use its own software implementation or a different engine/provider configuration. Measure the actual program, inspect its documented provider selection, and compare against a controlled baseline. /dev/crypto availability alone is not evidence that a TLS or storage workload is using it.
Size AEAD requests from the API fields
For authenticated encryption with additional data, CIOCCRYPTAEAD accepts the input/output buffers, payload length, additional-data pointer and length, IV pointer and length, and authentication-tag pointer. The API allows the additional data to be included in the authentication mode without treating it as encrypted payload. In a network protocol, that can cover metadata such as a record header while keeping the header readable, but the exact byte layout and nonce rules must come from the protocol you implement.
Before issuing the ioctl, validate every length against the allocated buffer and the selected session. Do not assume that a zero ivlen or maclen means “use the length I intended”; CIOCGSESSION2 documents zero as a request for the default IV/nonce or full MAC length. Keep the session setup and operation fields consistent, and pass buffers sized for the selected operation. The crypto(4) manual notes that the supplied key lengths must exactly match those expected by OpenCrypto and that output and MAC buffers must be large enough whenever the corresponding algorithm is requested.
Authentication failure is a normal, security-relevant error path. For CIOCCRYPT sessions using the documented fused encrypt-then-authenticate or AEAD mode, the manual says decryption requires the associated hash as input; an incorrect hash returns EBADMSG and leaves the output buffer unchanged. Treat any authentication failure as a rejected record: do not parse, persist, or forward plaintext from that operation, and do not retry with authentication disabled. When using the separate CIOCCRYPTAEAD structure, check its return status and tag contract for the exact release and selected algorithm before relying on a wrapper’s semantics.
Keep keys out of diagnostics, error messages, and crash dumps as far as the application architecture permits. Closing a device descriptor releases its associated session objects, but it is not a substitute for the application’s key-erasure and secret-management requirements. Likewise, use a cryptographically appropriate nonce policy; the ioctl’s ability to pass a nonce does not generate or guarantee unique nonces for you.
Diagnose failures without weakening policy
Use a staged check rather than changing sysctls or rebuilding a kernel immediately:
- Record the host release, kernel configuration or module state, and the current allow-soft setting (
kern.crypto.allow_softon the 15.0 source path, or the compatibilitykern.cryptodevallowsoftname if present). - Confirm
/dev/cryptois present and that the process has the intended device permissions. Do not broaden device access as a first response to an application error. - Inspect the requested algorithms, exact key lengths, IV/nonce and tag lengths, and whether the request needs a fused operation.
- Check which crypto drivers actually attached at boot and whether the request targets a device or class compatible with policy.
- Run a small known-answer test in a disposable environment, including a deliberately invalid authentication tag. Confirm both the success path and that the application rejects the failure path.
- Benchmark representative data sizes and concurrency only after correctness is established; record whether the measured path is hardware-backed, software-backed, or unknown.
The manual cautions that error checking and reporting are weak in parts of this interface, so preserve the ioctl errno and request context without logging secret material. A failed session or unsupported algorithm combination may require a different provider or API, not a policy relaxation. If software fallback is allowed, make that a documented operator choice and expose the actual selection in diagnostics where the application can verify it.
/dev/crypto is a low-level interface with explicit sessions and buffers. Its operational value comes from making dispatch, policy, and cleanup visible. It does not remove the need to validate provider availability, protocol nonce rules, application library configuration, or the security behavior of the surrounding program.
Related:
- FreeBSD KTLS: Verify TLS Session Offload and Its Limits
- FreeBSD GELI User-Key Rotation: Slot Testing, Metadata Backups, and Revocation
Sources:
- FreeBSD 15.0-RELEASE
crypto(4):/dev/crypto, session ioctls, AEAD, and provider policy - FreeBSD 15.0-RELEASE
aesni(4): driver configuration and CPU capability requirements - FreeBSD releng/15.0
crypto.c: allow-soft tunable and compatibility sysctl alias - FreeBSD releng/15.0
cryptodev.c: reject software-only provider requests when allow-soft is disabled - FreeBSD releng/15.0
aesni.c: accelerated-software provider classification