Technical writing

Swarm SDK device enrollment: how a new drone joins an authenticated fleet mesh

· 9 min read· AI Analytics
Swarm SDKCryptographyPost-quantumDrone

Every Swarm SDK fleet operates on authenticated identity. Before a drone can participate in the gossip mesh, send encrypted messages, or receive mission-critical commands, it needs a device certificate signed by the fleet's Fleet CA. This post covers the enrollment protocol — the process that transforms a fresh device with only factory-provisioned public keys into a trusted fleet participant.

What a device starts with: factory provisioning

At manufacturing time, before a device leaves the factory, three things happen. Two identity keypairs are generated on-device, both private keys are stored in secure storage, and the device receives the Root CA public key embedded in firmware as a static trust anchor.

The ML-KEM-768 identity keypair is generated using ml_kem_768::KeyPair::generate() with OS RNG. The X25519 identity keypair is generated using x25519_dalek::StaticSecret::random_from_rng(OsRng). On supported platforms, private keys land in a hardware secure element; on others they go into flash-encrypted storage. Neither private key is ever transmitted off-device.

The Root CA public key arrives as a static byte array compiled into the firmware image. This is the device's sole trust anchor before enrollment — it knows nothing about any Fleet CA until a Fleet CA certificate arrives signed by that root. A hardware-backed device ID (serial number or provisioned UUID) is also embedded at this stage.

The factory-provisioned state is captured in a single struct:

pub struct FactoryProvisionedIdentity {
    pub device_id: Uuid,
    pub kem_public_key: MlKem768PublicKey,
    pub dh_public_key: PublicKey,              // X25519 public key
    pub root_ca_public_key: &'static [u8; 32], // static trust anchor
    pub hardware_model: String,
    pub firmware_version: String,
}

Note that only public keys appear in this struct. The private keys are held in secure storage and accessed only through the platform's secure-storage API — they are never passed as function arguments or placed in heap-allocated memory accessible from application code.

The enrollment flow: four phases

Enrollment takes a device from factory state to a trusted mesh participant in four sequential phases:

  • Phase 1 — CSR generation: The device generates a Certificate Signing Request (CSR) containing its public keys and device ID, signed with a factory Ed25519 signing key to prove authenticity.
  • Phase 2 — CSR submission: The CSR is sent to the Fleet CA ground station via USB tether or a provisional RF link.
  • Phase 3 — Fleet CA signing: The ground station validates the CSR and issues a DeviceCertificate with a 90-day validity window, signed by the Fleet CA private key.
  • Phase 4 — Mesh announcement: The newly enrolled device broadcasts an EnrollmentAnnouncement over the gossip mesh so existing peers learn its certified identity and can establish X3DH sessions with it.

Phases 1 through 3 happen before the device has any mesh access. Phase 4 is the device's first act as a mesh participant.

Phase 1: CSR generation

The device constructs a CSR containing all information the Fleet CA needs to issue a certificate: both public keys, the device ID, hardware model, firmware version, the roles being requested, and the target fleet ID. The CSR is timestamped to allow the Fleet CA to reject stale requests.

pub struct DeviceCsrRequest {
    pub device_id: Uuid,
    pub kem_public_key: MlKem768PublicKey,
    pub dh_public_key: PublicKey,
    pub hardware_model: String,
    pub firmware_version: String,
    pub requested_roles: Vec<DroneRole>,  // COMBAT, RECON, RELAY, etc.
    pub fleet_id: Uuid,
    pub timestamp: DateTime<Utc>,
    pub signature: [u8; 64],    // Ed25519 over all fields above, using factory signing key
}

impl DeviceCsrRequest {
    pub fn generate(
        identity: &FactoryProvisionedIdentity,
        fleet_id: Uuid,
        roles: Vec<DroneRole>,
    ) -> Self {
        // ... build and sign the CSR
    }
}

The signature field uses a factory-provisioned Ed25519 signing key — a third keypair, separate from the KEM and DH keys, used only for enrollment authentication. This key is generated at the factory and its corresponding public key is registered in the fleet's device registry before the device ships.

The Ed25519 signing key is what prevents CSR forgery. An attacker who somehow learns a device's public keys (from observing mesh traffic, for example) cannot generate a valid CSR on its behalf — the CSR signature requires the factory signing key, which never leaves the device. The Fleet CA can verify the signature against the device key registry entry before issuing any certificate.

Phase 3: Fleet CA validation and certificate issuance

The Fleet CA ground station receives the CSR and runs four checks before issuing a certificate. First, it verifies the CSR signature against the device's registered factory key, looked up by device_id from the fleet's device registry. Second, it checks that the device_id is not in the revocation list. Third, it validates the firmware_version field against the approved firmware list — unapproved firmware images are rejected at enrollment. Fourth, it confirms the CSR timestamp is recent enough to rule out replay attacks.

If all checks pass, the Fleet CA issues a DeviceCertificate:

pub struct DeviceCertificate {
    pub device_id: Uuid,
    pub fleet_id: Uuid,
    pub kem_public_key: MlKem768PublicKey,
    pub dh_public_key: PublicKey,
    pub roles: Vec<DroneRole>,
    pub not_before: DateTime<Utc>,
    pub not_after: DateTime<Utc>,     // 90 days from issuance
    pub issued_by: Uuid,              // Fleet CA identifier
    pub signature: FleetCaSignature,  // Ed25519 signature over all above fields
    pub cert_serial: u64,             // monotonically increasing per Fleet CA
}

The cert_serial is monotonically increasing per Fleet CA and is used to detect re-enrollment attempts where a device tries to use an older certificate after a newer one has been issued. Peers that have seen a higher serial for a given device_id reject the older cert.

The 90-day validity window is the default. Operators can configure a shorter window (minimum 7 days) for high-risk deployments where certificate rotation needs to be more frequent. The Fleet CA hierarchy — Root CA signing Fleet CA certs, Fleet CA signing device certs — is described in depth in swarm-key-management; this article focuses on the enrollment flow that produces the device cert.

Enrollment transport options

The Swarm SDK supports three enrollment paths, differing in security posture and operational flexibility:

USB tether enrollment

The device connects via USB to a ground station application, which proxies the CSR to the Fleet CA and returns the signed certificate. This is the highest-security path: no RF exposure during enrollment means no opportunity for an over-the-air attacker to observe or interfere with the CSR exchange. For most fleet deployments where devices are physically present at a ground station before deployment, this is the recommended path.

Provisional RF enrollment

The device uses a provisional low-power RF link — on a separate frequency from the operational mesh — for enrollment. The provisional link uses the Root CA public key (already embedded in firmware) for bootstrap authentication, then upgrades to the Fleet CA certificate once enrollment completes. This path is used when USB tether is operationally impractical, such as when adding a drone to an already-deployed fleet.

Air-drop enrollment

For devices pre-loaded with CSRs (factory batch enrollment), the Fleet CA signs all CSRs offline and the resulting certificates are loaded onto devices via USB before deployment. The CSRs are generated at the factory, shipped alongside the device, and the Fleet CA operator signs them in batch — no device is present for the signing step. This path is used for large fleet deployments where per-device USB enrollment is logistically impractical.

Phase 4: gossip mesh announcement

Once enrolled, the device broadcasts an EnrollmentAnnouncement via the gossip mesh:

pub struct EnrollmentAnnouncement {
    pub certificate: DeviceCertificate,
    pub peer_prekeys: SignedPreKeyBundle,  // initial One-Time Prekeys for X3DH
    pub announced_at: DateTime<Utc>,
    pub mesh_capabilities: MeshCapabilities,  // frequency bands, relay capacity, etc.
}

The announcement bundles the device certificate together with a SignedPreKeyBundle — the initial set of One-Time Prekeys that peers need to initiate X3DH sessions with the new device. Distributing both in a single announcement means that existing mesh members receive everything they need to establish an encrypted session with the new device in one gossip round.

Existing mesh members receive the announcement, verify the certificate signature against the Fleet CA public key (which they already trust from their own enrollment), and add the new device to their peer table. The verification is the same chain the new device itself went through: the Fleet CA signature over the DeviceCertificate is valid, the cert is within its validity window, and the fleet_id matches the expected fleet.

Once the announcement has propagated — within approximately 30 seconds for a 30-node mesh at k=3 fanout — the new device can immediately participate in gossip mesh routing and establish X3DH sessions with any fleet member. The mesh treats the enrollment announcement as a normal gossip message: each node forwards it to k=3 peers, and the 50,000-message deduplication window prevents re-broadcast loops.

Pioneer device bootstrap: the first drone in a fleet

The first device in a new fleet has no ground station Fleet CA to connect to. There is no pre-existing Fleet CA certificate to verify, no device registry to look up factory keys against, and no peer certs to pre-provision. The Swarm SDK handles this edge case with a bootstrap mode.

One device is designated the Fleet CA seed node. In bootstrap mode, the seed node generates the Fleet CA keypair locally — on-device, using the same hardware RNG path as identity key generation. The Fleet CA private key is then either:

  • Securely transferred to the ground station over a USB connection (the standard path for fleets with a persistent ground station), after which the ground station holds the Fleet CA private key and the seed device retains only its own device cert; or
  • Held in the seed device itself for small autonomous fleets that have no persistent ground station. In this case the seed device acts as a mobile Fleet CA and must be protected accordingly — its loss is the loss of the fleet's signing authority.

The Fleet CA public key generated during bootstrap is distributed to all subsequently enrolled devices as part of their mission cert bundle. The Root CA signs the Fleet CA certificate via the standard offline ceremony — even in the bootstrap case, the Root CA remains the ultimate trust anchor, and the Fleet CA cert must be Root-CA-signed before any device cert it issues can be validated against the firmware-embedded root public key.

Re-enrollment at certificate expiry

Device certificates expire after 90 days. Re-enrollment is automatic: the SDK monitors the remaining validity of the current certificate and initiates a new CSR flow 7 days before expiry. The re-enrollment uses the same four-phase flow as initial enrollment, with one difference — the existing certificate is presented alongside the new CSR to allow the Fleet CA to confirm the device's continuity of identity before issuing the replacement cert.

The Fleet CA maintains continuity of device identity across re-enrollments. The device_id remains constant; the cert_serial increments. Peers that receive the new EnrollmentAnnouncement (broadcast after re-enrollment completes) recognize the device_id as a known peer and update the stored certificate rather than treating the device as new.

The 7-day re-enrollment window means that even if the ground station is temporarily unavailable, there is a one-week buffer before a device's certificate expires and it loses mesh access. A device with an expired certificate cannot authenticate to peers — it must complete re-enrollment before rejoining the mesh. This is intentional: expired certs are a signal that the normal operational cycle has been disrupted, and the device should not be trusted until the Fleet CA has re-validated it.

Revocation during enrollment

If a device's enrollment request arrives but the device has been flagged for revocation — for example, because it was previously deployed, captured, and its factory signing key is now suspected to be compromised — the Fleet CA rejects the CSR without issuing a certificate.

The rejection is not silent. The Fleet CA simultaneously broadcasts a RevocationMessage via the gossip mesh, ensuring that all existing mesh members drop the device from their peer tables immediately. Even if the device had somehow obtained a certificate from a previous enrollment cycle, the revocation message — signed by the Fleet CA and propagated via the same k=3 epidemic gossip as normal messages — causes every mesh member to refuse sessions with that device_id and purge any cached key material for it.

This means enrollment and revocation share the same propagation channel. An adversary who attempts to enroll a captured device triggers the same infrastructure that would otherwise be used to distribute SPK updates and peer announcements — and the response (revocation) propagates at the same speed as the attempt.


For the overall Swarm SDK cryptographic architecture this enrollment protocol is part of: Post-quantum mesh cryptography for drone swarms: the Swarm SDK design →

For the full Fleet CA hierarchy, 90-day certificate rotation, in-flight revocation, and emergency wipe procedure: Swarm SDK key management: device provisioning, certificate rotation, and revocation for autonomous drone systems →

For how enrolled devices establish encrypted sessions using X3DH and the DeviceCertificate bundle: Swarm SDK session establishment: X3DH prekey bundles and the initial drone-to-drone handshake →

For how the gossip mesh that carries EnrollmentAnnouncements is implemented — k=3 fanout, VecDeque deduplication, and anti-entropy reconciliation: Swarm SDK gossip mesh: bounded fanout routing, message deduplication, and network partition handling →