[package]
name = "krabitls"
version = "0.2.0"
edition = "2024"
rust-version = "1.87"
readme = "../README.md"
authors = ["kaidokert <kaidokert@gmail.com>"]
license = "Apache-2.0"
description = """
A TLS13 client lib for microcontrollers.
"""
repository = "https://github.com/kaidokert/krabitls-rs"
homepage = "https://github.com/kaidokert/krabitls-rs"
keywords = ["embedded", "no-std", "no-heap", "tls"]
categories = ["cryptography", "no-std", "no-std::no-alloc"]

# docs.rs builds the crate once and serves that build to everyone. Default
# features omit RSA, ChaCha20, and jedisct, so
# the rendered API would otherwise hide those types. Force every feature
# on for the published docs and pass `--cfg docsrs` so feature-gated
# items can grow `#[cfg_attr(docsrs, doc(cfg(feature = "X")))]` badges
# without affecting normal builds.
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["cert-der", "cipher-aes"]
# Expose internal helpers that aren't part of the TLS 1.3 API
dev-utils = []
# Optional RSA cert + CertificateVerify support (rsa_pss_rsae_sha256 + the
# self-signed cert's outer PKCS#1-v1.5). Pulls in rsa_heapless 0.2 (verify-only
# on the heapless path) plus sha2 0.11 under a renamed package — rsa_heapless
# builds on digest 0.11, one major ahead of the digest 0.10 we use for HKDF /
# transcript hashing, so the two sha2 versions sit side-by-side in an
# rsa-enabled build. ~1-2 KiB duplicate SHA-256 code is the cost of opting in;
# the default (rsa-disabled) binary is untouched. Supports both 1024-bit and
# 2048-bit RSA moduli via runtime dispatch.
rsa = ["dep:rsa_heapless", "dep:sha2_v11"]
# Alternate HKDF / SHA-256 backend wired to jedisct1's `hmac-sha256` crate
# (a standalone all-in-one impl with no `digest` / `crypto-common` /
# `generic-array` dependency). Pull this in when the binary should drop
# the RustCrypto `sha2 + hmac + hkdf + digest + crypto-common +
# generic-array` chain. AEAD stays on `aes-gcm` either way — jedisct1
# has no AES-GCM equivalent in the same family.
jedisct = ["dep:hmac-sha256"]
# Advertise TLS_CHACHA20_POLY1305_SHA256 alongside AES-128-GCM-SHA256.
chacha20 = ["dep:chacha20poly1305"]
# TLS_AES_128_GCM_SHA256 cipher suite. Default ON. Disable with
# `--no-default-features --features chacha20,...` for a ChaCha-only build
# (drops `aes-gcm` + `aes` + `ghash` deps). At least one of `cipher-aes`
# or `chacha20` must be active.
cipher-aes = ["dep:aes-gcm"]
# Sub-feature of `rsa`: drop the PKCS#1-v1.5 cert outer-signature path.
# Cert parser rejects `sha256WithRSAEncryption`; only `rsassa-pss` is
# accepted on cert outer signatures. Saves ~1 KiB .text vs the default
# (both schemes linked) at the cost of refusing PKCS#1-v1.5-signed RSA
# certs — i.e. most real-world CA-issued certs. For footprint demos and
# controlled-profile deployments where the cert is known to be PSS-signed.
# CertificateVerify always uses PSS for our advertised scheme so this
# feature doesn't affect handshake semantics.
rsa_pss_only = ["rsa"]
# Sub-feature of `rsa`: drop the RSA-1024 bigint width. Only 2048-bit
# moduli are accepted (parser + verify both reject 128 B modulus).
# Saves ~2-4 KiB .text by dropping the U1024 monomorphizations of
# `public_key_from_be_bytes`, `rsa_encrypt`, and the modmath kernels
# (`cios_mont_mul`, `wide_redc`, `mod_exp2`) that LTO can't otherwise
# prove unreachable through the cached `RsaVerifierKey` enum.
rsa_2048_only = ["rsa"]
# Cert parser backend selector + `der` gate. On (default) → der-crate-backed
# parser, and the cert validity-window check (`.clocked()`) is available since
# it decodes UTCTime/GeneralizedTime through `der`. Off → in-tree TLV walker,
# `der` dropped entirely (~-4 KiB .text), and validity is unavailable (the
# default `NoClock` strategy is the only one that compiles).
cert-der = ["dep:der"]
# Match IP-literal hostnames against SAN `iPAddress` entries. Without it,
# IP literals fall through to `HostnameMismatch`. Saves ~2 KiB of
# `core::net::parser` on DNS-only embedded deployments. Default OFF.
ip-host = []
# Optional ML-DSA (FIPS 204) signature-verification backend, gated exactly
# like `rsa`. Pulls in krabipqc 0.1.1 (no_std, no-alloc) which carries its own
# keccak/sha3 chain — none of it links into the default build. Verify only:
# the keygen/sign facade is test-only. Covers ML-DSA-44/65/87.
mldsa = ["dep:krabipqc"]
# Optional ML-KEM-768 (FIPS 203) key encapsulation, the client side of an
# `X25519MLKEM768` hybrid TLS key exchange. Same krabipqc dependency as `mldsa`;
# verification/handshake wiring is built on top in later steps.
mlkem = ["dep:krabipqc"]

[dependencies]
embedded-io = { version = "0.7.1", default-features = false }
hmac-sha256 = { version = "1", default-features = false, features = ["traits010"], optional = true }
rsa_heapless = { version = "0.2.1", default-features = false, features = ["modmath"], optional = true }
sha2_v11 = { package = "sha2", version = "0.11", default-features = false, features = ["oid"], optional = true }

# RustCrypto stable line — all share generic-array 0.14 / crypto-common 0.1.
aes-gcm = { version = "0.10", default-features = false, features = ["aes", "zeroize"], optional = true }
# Trait crate shared by aes-gcm + chacha20poly1305 (both use aead 0.5).
# Direct dep so the AEAD-trait imports stay valid even if `aes-gcm` later
# becomes an optional `feature = "cipher-aes"` dep.
aead = { version = "0.5", default-features = false }
chacha20poly1305 = { version = "0.10", default-features = false, optional = true }
sha2 = { version = "0.10", default-features = false, features = ["force-soft-compact"] }
digest = { version = "0.10", default-features = false }
hmac = { version = "0.12", default-features = false }
hkdf = { version = "0.12", default-features = false }
ed25519_heapless = { version = "0.2.1", default-features = false, features = ["fixed-bigint", "sha512-sha2"] }
fixed-bigint = { version = "0.3", default-features = false, features = ["use-unsafe", "zeroize"] }
der = { version = "0.8.0", default-features = false, features = ["oid"], optional = true }
zeroize = { version = "1.8", default-features = false, features = ["derive"] }
heapless = { version = "0.9", default-features = false }
subtle = { version = "2.6", default-features = false }
thiserror = { version = "2", default-features = false }
signature = { version = "3", default-features = false }
rand_core = { version = "0.10", default-features = false }
krabipqc = { version = "0.1.1", default-features = false, optional = true }

# Deterministic SeededRng + CannedTransport for the host facade replay
# tests. Dev-only so the seed-mode RNG (a `TryCryptoRng` that is NOT a
# CSPRNG) never reaches a published build. The dev-dependency cycle back to
# krabitls is allowed by Cargo. `default-features = false` so the fixtures
# crate inherits whatever cipher this test build selects instead of forcing
# `cipher-aes`.
[dev-dependencies]
krabitls_fixtures = { path = "../krabitls_fixtures", default-features = false }
