Files
alknet/tasks/tls/server-extract.md
T
deepseek-v4-pro 4ced71f44a tasks: decompose phases 0-1 of crate extraction into implementation tasks
Phase 0 (core/connection-credentials): purely additive — add
ConnectionCredentials + RemoteIdentity to alknet-core. No call crate
changes. ~40 lines, zero breakage.

Phase 1 (tls/*): greenfield alknet-tls crate in 5 tasks:
- tls/crate-init: Cargo.toml, deps, module skeleton
- tls/server-extract: TlsServerConfig + server TLS code from endpoint.rs
- tls/client-extract: TlsClientConfig + client TLS code from call_client.rs
- tls/tests: 32 TLS tests moved and adapted
- tls/review-tls: phase gate review checkpoint

All old code stays duplicated — purely additive phases. Prunes in 4-5.
2026-07-17 09:29:20 +00:00

6.7 KiB

id, name, status, depends_on, scope, risk, impact, level
id name status depends_on scope risk impact level
tls/server-extract Extract server-side TLS code from alknet-core/endpoint.rs into alknet-tls pending
tls/crate-init
moderate medium component implementation

Description

Phase 1, Task 2 of the crate extraction. Extract the server-side TLS setup code from crates/alknet-core/src/endpoint.rs (lines 493-934) into crates/alknet-tls/src/server.rs and crates/alknet-tls/src/signing.rs + crates/alknet-tls/src/pem.rs (shared helpers).

The old code stays in endpoint.rs (duplicated) — no breakage. The new crate is self-contained and builds standalone.

Types to extract

From endpoint.rs lines 493-934:

Type/Function Lines Destination
TlsSetup struct + new() + new_acme() 493-611 server.rs
build_quinn_server_config_from_rustls() 614-624 server.rs
build_rustls_server_config() 626-674 server.rs
build_iroh_endpoint() 676-703 server.rs (feature-gated on iroh)
load_cert_chain() 705-714 pem.rs (shared)
load_private_key() 716-730 pem.rs (shared)
SelfSignedCert struct 732-736 server.rs
generate_self_signed_cert() 738-755 server.rs
AcceptAnyCertVerifier struct + impls 757-834 server.rs
RawKeyCertResolver struct + impls 836-873 server.rs
Ed25519SigningKey struct + impls 875-933 signing.rs (shared)

New public API types

The extracted code currently uses free functions and private structs. Wrap them in public API types for the crate:

// server.rs

/// Server-side TLS configuration, transport-agnostic.
/// Wraps a `rustls::ServerConfig` plus optional ACME state.
pub struct TlsServerConfig {
    pub(crate) rustls_config: rustls::ServerConfig,
    #[cfg(feature = "acme")]
    pub(crate) acme_state_handle: Option<tokio::task::JoinHandle<()>>,
}

impl TlsServerConfig {
    /// Build a server config from a `TlsIdentity` and ALPN list.
    /// ACME identities spawn a background cert-renewal task.
    pub async fn new(
        tls_identity: &alknet_core::config::TlsIdentity,
        alpns: &[Vec<u8>],
    ) -> Result<Self, TlsError> { ... }

    /// Convert to a `quinn::ServerConfig` for QUIC transport.
    #[cfg(feature = "quinn")]
    pub fn for_quinn(self) -> Result<quinn::ServerConfig, TlsError> { ... }
}
// signing.rs

/// Ed25519 signing key usable as both a rustls `SigningKey` and `Signer`.
/// Consolidated — one copy used by both server (`RawKeyCertResolver`) and
/// client (`RawKeyClientCertResolver`).
pub struct Ed25519SigningKey { ... }
// pem.rs

/// Load a PEM-encoded certificate chain from a file path.
pub fn load_cert_chain(path: &Path) -> Result<Vec<CertificateDer<'static>>, TlsError> { ... }

/// Load a PEM-encoded private key from a file path.
pub fn load_private_key(path: &Path) -> Result<PrivateKeyDer<'static>, TlsError> { ... }

TlsError

Define a unified error type:

#[derive(Debug, thiserror::Error)]
pub enum TlsError {
    #[error("TLS config error: {0}")]
    Config(String),
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),
    #[error("certificate error: {0}")]
    Cert(String),
}

Adaptations

  1. Error types: Replace EndpointError::TlsConfig(...) with TlsError::Config(...) or TlsError::Io(...). The EndpointError type stays in core — the extracted code uses TlsError instead.
  2. Imports: Update all crate::config::* imports to alknet_core::config::*. Update crate::fingerprint::* to alknet_core::fingerprint::*.
  3. Ed25519SigningKey: Move to signing.rs as a shared type. Both server.rs and (later) client.rs will use it from there.
  4. load_cert_chain / load_private_key: Move to pem.rs as shared functions. Both server.rs and (later) client.rs will use them from there.
  5. build_iroh_endpoint: This is an iroh-specific builder, not pure TLS. Gate on #[cfg(feature = "iroh")] and depend on alknet-core/iroh. If the iroh dep is too heavy for alknet-tls, leave it in core for now and note as a TODO.
  6. Feature gates: AcceptAnyCertVerifier, RawKeyCertResolver, SelfSignedCert, generate_self_signed_cert, build_rustls_server_config, build_quinn_server_config_from_rustls are gated on #[cfg(feature = "quinn")]. build_iroh_endpoint is gated on #[cfg(feature = "iroh")]. TlsSetup::new_acme is gated on #[cfg(feature = "acme")].

What stays in core

The old code in endpoint.rs lines 493-934 is not deleted — it stays as a duplicate. The prune happens in Phase 4. This task only adds code to alknet-tls.

Acceptance Criteria

  • crates/alknet-tls/src/server.rs contains TlsServerConfig, TlsSetup, build_rustls_server_config, build_quinn_server_config_from_rustls, RawKeyCertResolver, AcceptAnyCertVerifier, SelfSignedCert, generate_self_signed_cert
  • crates/alknet-tls/src/signing.rs contains Ed25519SigningKey with SigningKey + Signer impls
  • crates/alknet-tls/src/pem.rs contains load_cert_chain + load_private_key
  • TlsServerConfig::new() accepts &TlsIdentity + &[Vec<u8>] and returns Result<Self, TlsError>
  • TlsServerConfig::for_quinn() converts to quinn::ServerConfig (feature-gated)
  • TlsError enum has Config, Io, Cert variants
  • All extracted code uses TlsError (not EndpointError)
  • All extracted code imports from alknet_core (not crate::)
  • Feature gates correct: quinn for TLS types, acme for ACME, iroh for iroh builder
  • cargo check -p alknet-tls succeeds (all feature combos)
  • cargo clippy -p alknet-tls succeeds with no warnings
  • cargo test -p alknet-core still passes (old code untouched)
  • cargo test -p alknet-call still passes (old code untouched)

References

  • docs/research/alknet-crate-extraction/findings.md — Phase 1, server-side extraction
  • crates/alknet-core/src/endpoint.rs — lines 493-934 (source code to extract)
  • crates/alknet-core/src/config.rs — TlsIdentity, Ed25519SecretKey, AcmeDirectory
  • crates/alknet-core/src/fingerprint.rs — extract_ed25519_raw_key_from_spki

Notes

This is the largest single extraction in Phase 1 (~440 lines). The code is well-understood and tested — the main work is adapting error types and imports. Ed25519SigningKey and load_cert_chain/load_private_key are extracted to shared modules because the client-side extraction (next task) also needs them. The build_iroh_endpoint function may be deferred if the iroh dep is too heavy for alknet-tls — note as TODO if so. The old code in endpoint.rs is NOT deleted — that's Phase 4.

Summary

To be filled on completion