Getting Started Guide¶
The FDO project provides a reference implementation of the FIDO specification by the FIDO Alliance.

FDO (FIDO device onboard) provides a fast and more secure way to onboard a device to any device management system. A unique feature of FDO is the ability for the device owner to select the IoT platform at a later stage in the device life cycle. The secrets or configuration data may also be created or chosen at this later stage.
This document provides a quick walk through the E2E flow. Included in this guide:
- Quick Overview of FDO
- Building FDO PRI Source
- Starting FDO Service Containers
- Running E2E for PRI device
- Building Client-SDK Source
- Running E2E for Client-SDK device
- Enabling ServiceInfo
- Keystore Management
Quick Overview of FDO¶
FDO contains 3 major server-side components and 1 client-side component. The server-side components include Manufacturer, RV, and Owner Service. The client-side includes device implementation in Java (PRI) or C (Client-sdk-fidoiot).
FDO consists of four sets of protocols namely DI, TO0, TO1, and TO2.
-
DI (Device Initialization protocol)
- Between Device & Manufacturer (msg 10-13).
- Initiated by Device and Device contacts Manufacturer Service.
- Includes creation & insertion of FDO credentials into newly manufactured device. Credential includes RVInfo which is used by device to connect with RV during T01 protocol
- Customers can take ownership of device after DI by extending the Ownership voucher to a particular customer.
- Ownership voucher is a credential file, passed through the supply chain, that allows an Owner to verify the Device and gives the Device a mechanism to verify the Owner.
-
TO0 (Transfer of Ownership 0 Protocol)
- Between Owner & Rendezvous (RV) server (msg 20-23).
- Initiated by Owner once it receives Ownership voucher and Owner contacts RV server.
- TO0 creates a mapping between GUID and owner address and is stored in RV server's database.
- Basically it creates a mapping like GUID=>OwnerAddress
- OwnerAddress can be DNS/IP or combination of both.
-
T01 (Transfer of Ownership 1 Protocol)
- Between Device & Rendezvous (RV) server (msg 30-33).
- Initiated by Device. The Device contacts RV server using the rvInfo directives collected during DI.
- During T01, Device identifies itself to RV server and collects the respective mapping of Owner address based on its GUID. This mapping was stored in RV during TO0.
- The Device can use the collected OwnerAddress to contact Owner during TO2.
-
T02 (Transfer of Ownership 2 Protocol)
- Between Device & Owner Server (msg 60-71)
- Initiated by Device using the OwnerAddress collected during TO1.
- Device contacts Owner Server and establishes trust and then performs Ownership Transfer.
- During T02, Owner can transfer ServiceInfo modules to the device. These modules can include executable scripts, file payloads, and much more.
Building FDO PRI Source¶
Requirements
- Check the System Requirements
- When working behind a proxy, ensure to set proper proxy variables.
- Follow the steps to setup Docker* environment.
- Follow the steps to setup Docker* proxy.
- Follow the steps to set the right proxy settings. (Includes documentation for system wide proxy configuration)
1. Clone the PRI-fidoiot repository
git clone https://github.com/secure-device-onboard/pri-fidoiot.git
2. Build PRI-fidoiot:
Notes
For the instructions in this document, <fdo-pri-src>
refers to the path of the FDO PRI folder 'pri-fidoiot'.
Read more about PRI source building.
FDO PRI source can be built in two ways:
- Using the Maven build system to build FDO PRI source.
cd <fdo-pri-src>
mvn clean install
2. Using Docker container to build FDO PRI source
cd <fdo-pri-src>/build
sudo docker-compose up --build
The build stage generates artifacts and stores them in component-samples/demo
directory.
Notes
During the build stage, the following error messages may be displayed on the console. These error messages are a result of the discrepancy of logging levels during the build stage and can be ignored.
[ERROR] Picked up _JAVA_OPTIONS: -Dhttp.proxyHost= -Dhttp.proxyPort= -Dhttps.proxyHost= -Dhttps.proxyPort=
[ERROR] WARNING: An illegal reflective access operation has occurred
[ERROR] WARNING: Illegal reflective access by org.apache.catalina.loader.WebappClassLoaderBase to field java.io.ObjectStreamClass$Caches.localDescs
[ERROR] WARNING: Please consider reporting this to the maintainers of org.apache.catalina.loader.WebappClassLoaderBase
[ERROR] WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
[ERROR] WARNING: All illegal access operations will be denied in a future release
Starting FDO Server-side Containers¶

Key Generation for FDO Server-side Containers¶
Run the below commands to generate all the required keys for the Server-side containers.
cd <fdo-pri-src>/component-samples/demo/scripts/
bash keys_gen.sh .
cp -r creds/* ../
All the generated keys are now copied to the respective components.
Starting the FDO PRI Manufacturer Server¶
FDO Manufacturer is an application that runs in the factory, which implements the initial communications with the Device, as part of the Device Initialize Protocol (DI). The manufacturer creates an Ownership Voucher based on the credentials received during DI and extends the voucher to the respective owner.
Run the below commands, in a separate console, to start the Manufacturer.
cd <fdo-pri-src>/component-samples/demo/manufacturer/
sudo docker-compose up --build
Once the Manufacturer has successfully started, the following output is displayed

Starting the FDO PRI Rendezvous (RV) Server¶
RV Server is a network server or service (For example, on the Internet) that acts as a rendezvous point between a newly powered on Device and the Owner Onboarding Service.
Run the below commands, on a seperate console, to start the RV server.
cd <fdo-pri-src>/component-samples/demo/rv/
sudo docker-compose up --build
Once the RV instance has successfully started, the following output is displayed

Starting the FDO PRI Owner Server¶
Owner is an entity that is able to prove ownership to the Device using an Ownership Voucher and a private key for the last entry of the Ownership Voucher. Owner supports the transfer of Serviceinfo to the Device.
Run the below commands, on a separate console, to start the Owner Server.
cd <fdo-pri-src>/component-samples/demo/owner/
sudo docker-compose up --build
Once the Owner instance has successfully started, the following output is displayed

Notes
- Proper keystore management to be considered before using the services in production environment.
- To0scheduling interval property can be modified in the component-sample/demo/owner/service.yml.
Update to0-scheduler:
interval: 120
- Read more about starting PRI services.
Running E2E for PRI Device¶
-
Start FDO Service Containers.¶
-
Start Device Initialization (DI)¶
When DI is initiated, device contacts manufacturer. DI includes the insertion of FDO credentials into device during the manufacturing process and creation of ownership voucher.
On a new console, key in the following commands
Notes
Make sure that di-url
is set to the correct address in service.yml
of device. The default di-url
value for standalone manufacturer is http://localhost:8039
.
cd <fdo-pri-src>/component-samples/demo/device
java -jar device.jar
Expect the following line on successful DI completion.
DI complete, GUID is <guid>
After completion of DI, the FDO credentials are stored into credentials.bin
file. The credentials file includes rvinfo
from manufacturer, which is later used by device to contact RV server, once it is powered on at the client side. The initialized device is then boxed and sold to customers.
Additional_configurations
- Additional arguments for configuring PRI device.
- Configuring PRI device for HTTPS/TLS communication.
- Read more about Device Intialization.
Voucher Extension & TO0 for PRI Device¶

During TO0, the FDO Owner identifies itself to Rendezvous Server and establishes the mapping between GUID and Owneraddress. TO0 ends with RV Server having an entry in a table that associates the Device GUID with the Owner Service’s rendezvous 'blob'. Follow the given steps to access database table.
Execute the following script to initiate TO0.
cd <fdo-pri-src>/component-samples/demo/scripts
bash extend_upload.sh -s serial_no
or
Following the steps to manually initiate the T00.
curl -D - --digest -u ${api_user}:${owner_api_passwd} --location --request GET "http://${owner_ip}:${onr_port}/api/v1/certificate?alias=${attestation_type}" -H 'Content-Type: text/plain' -o owner_cert.txt
curl -D - --digest -u ${api_user}:${mfg_api_passwd} --location --request POST "http://${mfg_ip}:${mfg_port}/api/v1/mfg/vouchers/${serial_no}" --header 'Content-Type: text/plain' --data-raw "<content-of-owner_cert>" -o ${serial_no}_voucher.txt)
curl -D - --digest -u ${api_user}:${onr_api_passwd} --location --request POST "http://${onr_ip}:${onr_port}/api/v1/owner/vouchers/" --header 'Content-Type: text/plain' --data-raw "$extended_voucher" -o ${serial_no}_guid.txt)
curl -D - --digest -u ${api_user}:${onr_api_passwd} --location --request GET "http://${onr_ip}:${onr_port}/api/v1/to0/${device_guid}" --header 'Content-Type: text/plain')
Warning
Make sure to replace generated-password
with api_password
property present in component-samples/demo/<component>/service.env
file.
Here, the initial two curl calls are to collect the Ownership voucher from Manufacturer server and the final two curl calls are to upload the collected voucher to Owner. Using the received voucher, Owner initiates TO0 with RV Server using the rvAddress present in Voucher.
Warning
Make sure you are getting status 200 OK
for the curl calls. If you are facing issue with localhost
curl calls, try with IP address instead of localhost.**
Wait for TO0 finished for
Expect the following message on successful TO0 completion.
TO0 Client finished for GUID <guid>
After the completion of TO0, RV Server will have an entry in a table that associates the Device GUID with the Owner Address.
Note
- Keystore Management needs to be taken care, if PRI Rendezvous server and PRI Owner server is not running on the same machine.
- You can enable ServiceInfo at this stage. Follow the instructions to enable ServiceInfo.
TO1 and TO2¶
During T01, Device identifies itself to the Rendezvous Server. Obtains mapping to connect to the Owner’s IP address. During T02, the Device contacts Owner and establishes trust and then performs Ownership Transfer.
During T02, Owner can transfer ServiceInfo modules to the device. These modules can include executable scripts, file payloads. Read more about serviceInfo transfers.
cd <fdo-pri-src>/component-samples/demo/device
java -jar device.jar
Wait for TO2 protocol completed message and Device is onboarded Successfully.
Expect the following message on successful TO2 completion.
TO2 completed successfully.
Building Client-SDK Source¶
FDO Client-SDK source can be build by:
-
Follow instructions in the documentation to install dependencies.
-
Clone the repository
git clone https://github.com/secure-device-onboard/client-sdk-fidoiot.git
Note
For the instructions in this document, <client-sdk-src>
refers to the path of the FDO Client-SDK source folder 'client-sdk-fidoiot'.
3. Execute build.sh script
cd <client-sdk-src>
./build.sh
The build script generates artifacts and stores them in ./build/
directory.
Running E2E Demo for FDO Client-SDK¶
1. Start FDO Service Containers.¶
2. Start Device Initialization (DI)¶
When DI is initiated, device contacts manufacturer. DI includes the insertion of FDO credentials into device during the manufacturing process and creation of ownership voucher.
On a new console, key in the following commands
cd <client-sdk-src>
./build/linux-client
Additional_configurations
- Read more on Client-SDK Device Initialization.
- Configuring Client-SDK device for Proxy Network.
- Follow instructions in the documentation, to update Manufacturer's address.
Voucher Extension for Client-SDK Device¶
During TO0, the FDO Owner identifies itself to Rendezvous Server, establishes the mapping of GUID to the Owner IP address. TO0 ends with RV Server having an entry in a table that associates the Device GUID with the Owner Service’s rendezvous 'blob.'
curl -D - --digest -u ${api_user}:${owner_api_passwd} --location --request GET "http://${owner_ip}:${onr_port}/api/v1/certificate?alias=${attestation_type}" -H 'Content-Type: text/plain' -o owner_cert.txt
curl -D - --digest -u ${api_user}:${mfg_api_passwd} --location --request POST "http://${mfg_ip}:${mfg_port}/api/v1/mfg/vouchers/abcdef" --header 'Content-Type: text/plain' --data-raw "<content-of-owner_cert>" -o voucher.txt)
curl -D - --digest -u ${api_user}:${onr_api_passwd} --location --request POST "http://${onr_ip}:${onr_port}/api/v1/owner/vouchers/" --header 'Content-Type: text/plain' --data-raw "$extended_voucher" -o ${serial_no}_guid.txt)
curl -D - --digest -u ${api_user}:${onr_api_passwd} --location --request GET "http://${onr_ip}:${onr_port}/api/v1/to0/${device_guid}" --header 'Content-Type: text/plain')
Warning
Make sure to replace generated-password
with api_password
property present in component-samples/demo/<component>/creds.env
file.
Here, the initial curl call is to collect the Ownership voucher from Manufacturer server and the final curl call is to upload the collected voucher to Owner. Using the received voucher, Owner initiates TO0 with RV Server using the rvAddress present in Voucher.
Warning
Make sure you are getting status 200 OK
for the curl calls. If you are facing issue with localhost
curl calls, try with IP address instead of localhost.**
Wait for TO0 to finish for
Expect the following message on successful TO0 completion.
TO0 Client finished for GUID <guid>
Notes
- Keystore Management needs to be taken care, if PRI Rendezvous server and PRI Owner server is not running on the same machine.
- You can enable ServiceInfo at this stage. Follow the instructions to enable ServiceInfo.
TO1 and TO2¶
During T01, Device identifies itself to the Rendezvous Server. Obtains mapping to connect to the Owner’s IP address. During T02, the Device contacts Owner and establishes trust and then performs Ownership Transfer.
During T02, Owner can transfer ServiceInfo modules to the device. These modules can include executable scripts, file payloads. Read more about serviceInfo transfers.
cd <client-sdk-src>
./build/linux-client
Wait for TO2 protocol completed message
Expect the following message on successful TO completion.
Device onboarded successfully.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@FIDO Device Onboard Complete@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Enabling ServiceInfo Transfer¶
- Create a sample linux64.sh shell script.
#!/bin/bash wget https://raw.githubusercontent.com/secure-device-onboard/pri-fidoiot/master/SECURITY.md filename=SECURITY.md cksum_tx=2749598590 cksum_rx=$(cksum $filename | cut -d ' ' -f 1) if [ $cksum_tx -eq $cksum_rx ]; then echo "Device onboarded successfully." echo "Device onboarded successfully." > result.txt else echo "ServiceInfo file transmission failed." echo "ServiceInfo file transmission failed." > result.txt fi
This script downloads the SECURITY.md file and checks the integrity of file against the pre-computed checksum value.
-
cURL command to transfer executable resource.
$ curl --location --digest -u apiUser: --location --request POST 'http://localhost:8080/api/v1/owner/resource?filename=linux64.sh' --header 'Content-Type: text/plain' --data-binary '@path-to-executable/linux64.sh'
-
cURL command to update ServiceInfo instructions. Eg:
$ curl -D - --digest -u apiUser: --location --request POST 'http://localhost:8080/api/v1/owner/svi' --header 'Content-Type: text/plain' --data-raw '[{\"filedesc\" : \"payload.bin\",\"resource\" : \"payload.bin\"},{\"filedesc\" : \"linux64.sh\",\"resource\" : \"linux64.sh\"},{\"exec\" : [\"/bin/bash\",\"linux64.sh\"]}]'
Keystore Management¶
Generating Self-signed keys for HTTPS/TLS Communication.¶
-
Generate key and certificate.
openssl req \ -x509 \ -newkey rsa:2048 \ -sha256 \ -days 3560 \ -nodes \ -keyout tls.key \ -out tls.crt \ -subj '/CN=fdo' \ -extensions san \ -config <( \ echo '[req]'; \ echo 'distinguished_name=req'; \ echo '[san]'; \ echo 'subjectAltName=DNS:localhost,IP:<ip-address>')
Update
<ip-address>
with the IP address of machine running the FDO service. -
Generate Keystore using fresh key and certificate.
openssl pkcs12 -export -in tls.crt -inkey tls.key -out ssl.p12
- Copy the
ssl.p12
file intocomponent-samples/demo/<component>/certs/
folder. - Update the respective
.env
file with proper keystore credentials.
- Copy the
-
Adding generated certificate into the truststore.
keytool -import -alias fdo -file tls.crt -storetype PKCS12 -keystore truststore
Notes
- Read more about key generation.
- You can update the key type, by modifying the
-newkey
attribute during the key generation stage. - You can add multiple IP addresses in the
subjectAltName
attribute.