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.
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 |
|
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
- Error types: Replace
EndpointError::TlsConfig(...)withTlsError::Config(...)orTlsError::Io(...). TheEndpointErrortype stays in core — the extracted code usesTlsErrorinstead. - Imports: Update all
crate::config::*imports toalknet_core::config::*. Updatecrate::fingerprint::*toalknet_core::fingerprint::*. Ed25519SigningKey: Move tosigning.rsas a shared type. Bothserver.rsand (later)client.rswill use it from there.load_cert_chain/load_private_key: Move topem.rsas shared functions. Bothserver.rsand (later)client.rswill use them from there.build_iroh_endpoint: This is an iroh-specific builder, not pure TLS. Gate on#[cfg(feature = "iroh")]and depend onalknet-core/iroh. If the iroh dep is too heavy foralknet-tls, leave it in core for now and note as a TODO.- Feature gates:
AcceptAnyCertVerifier,RawKeyCertResolver,SelfSignedCert,generate_self_signed_cert,build_rustls_server_config,build_quinn_server_config_from_rustlsare gated on#[cfg(feature = "quinn")].build_iroh_endpointis gated on#[cfg(feature = "iroh")].TlsSetup::new_acmeis 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.rscontainsTlsServerConfig,TlsSetup,build_rustls_server_config,build_quinn_server_config_from_rustls,RawKeyCertResolver,AcceptAnyCertVerifier,SelfSignedCert,generate_self_signed_certcrates/alknet-tls/src/signing.rscontainsEd25519SigningKeywithSigningKey+Signerimplscrates/alknet-tls/src/pem.rscontainsload_cert_chain+load_private_keyTlsServerConfig::new()accepts&TlsIdentity+&[Vec<u8>]and returnsResult<Self, TlsError>TlsServerConfig::for_quinn()converts toquinn::ServerConfig(feature-gated)TlsErrorenum hasConfig,Io,Certvariants- All extracted code uses
TlsError(notEndpointError) - All extracted code imports from
alknet_core(notcrate::) - Feature gates correct:
quinnfor TLS types,acmefor ACME,irohfor iroh builder cargo check -p alknet-tlssucceeds (all feature combos)cargo clippy -p alknet-tlssucceeds with no warningscargo test -p alknet-corestill passes (old code untouched)cargo test -p alknet-callstill 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.
Ed25519SigningKeyandload_cert_chain/load_private_keyare extracted to shared modules because the client-side extraction (next task) also needs them. Thebuild_iroh_endpointfunction may be deferred if the iroh dep is too heavy foralknet-tls— note as TODO if so. The old code inendpoint.rsis NOT deleted — that's Phase 4.
Summary
To be filled on completion