A device certificate is a unique identity credential that the IoT Platform issues for a device. To help you quickly read device certificate information from a downloaded CSV file and write it to devices on your production line, the IoT Platform provides a device certificate distribution tool. This document explains how to use the tool to adapt your production line and improve mass production efficiency.
Solution overview
The following diagram shows the architecture of the IoT Platform device certificate distribution tool.
The tool uses a server-client architecture. The following flowchart shows the interaction between the server and the client.
- Server: The server is provided by the IoT Platform. You can use it directly after you download it.
You can use the provided Node.js software development kit (SDK) to verify that the server-side link works correctly. For more information, see the Use the server-side tool section in this document.
- Client: The client is deployed on a production line programmer or integrated into the product firmware. You must develop the client yourself. The following table compares these two deployment methods.
The IoT Platform provides a C SDK for your reference to help you quickly integrate the client. For more information, see the Develop a client using the C SDK section in this document. After you integrate the C SDK, you must also integrate a method for writing device certificates into the client.
Client deployment method Scenarios Description Features Integrated into device firmware The production line has no programmers for writing device certificates to chips or devices. In this solution, the client requests identity information from the server after the device powers on. After the client obtains the device certificate, it writes the information to the device's Non-Volatile RAM (NVRAM) and Flash memory. In this solution, you must implement the following:
- A function to trigger the client to obtain the device certificate.
- An operation to write the information to NVRAM and Flash after the client obtains the device certificate.
- No dedicated programmers for writing device certificates are required on the production line.
- The device must implement the client functions, which consumes some of the device's storage space.
- Allows you to obtain identity information in batches.
Deployed on a production line programmer The production line has instruments, such as programmers, for writing device certificates to chips or devices. In this solution, the programming software implements the client functions to request identity information from the server. After obtaining the device certificate, the software uses a programmer to write the information to the device's NVRAM and Flash. Alibaba Cloud IoT provides the communication protocol for the production line distribution application. In this solution, you must modify the production line programming tool to obtain device certificates from the distribution application according to this protocol.
- The device does not need to implement the client functions. This saves storage space that would otherwise be used for obtaining identity information.
- You must modify the programmer's software.
- You can configure the number of programmers based on the quantity and scale of production devices on the production line.
Server-client protocol description
The client and server communicate using an HTTP interface. The client sends a POST request to the server. The request protocol is in JSON format and is located in the request body.
| Field | Type | Required | Description |
| ProductKey | string | Yes | The product identifier. It is generated when you create a product in the IoT Platform console. |
| DeviceID | string | No | The device ID. It must be unique. |
| Action | Integer | Yes | The operation.
|
The following sections provide examples of request and response data.
- Request for a device certificate from a client to a server
{ "ProductKey":"a1xxxxNW", "DeviceID":"AAxxxx22", "Action":0 } - Device certificate data distributed from a server to a client
{ "ProductKey":"a1xxxxNW", "ProductSecret":"XmDxxxx9R", "DeviceSecret":"NmMExxxxjE5", "CRC32":"B5488744", // For more information about CRC32, see the following section. "DeviceName":"ZTMxxxxxkUy", "DeviceID":"AABxxxx22", "Status":"OK" } - Request to update the status after a successful write operation
{ "ProductKey":"a1xxxxW", "DeviceID":"AAxxxx22", "Action":1 } - Response for a successful status update
{ "ProductKey": "a1xxxxNW", "DeviceID": "AAxxxx22", "Status": "OK" }
The data that the server distributes to the client uses the standard CRC32 checksum algorithm (CRC32 calculation tool URL). The polynomial is 04C11DB7. The initial value and the final exclusive OR (XOR) value are both FFFFFFFF. Both the input and output are inverted. The checksum payload is the device credential. For Wi-Fi devices, the payload consists of ProductKey, ProductSecret, DeviceName, and DeviceSecret. For Bluetooth devices, the payload consists of ProductKey, ProductSecret, DeviceName, DeviceSecret, and ProductID. The checksum result is a 4-byte hexadecimal value.
The following example shows how to use the CRC32 calculation and verification tool.
- Java reference implementation
import java.nio.ByteBuffer; import java.util.zip.CRC32; public class example { public static void main(String[] args){ // This is a user-supplied string. String pk = "a1xxxxH"; String dn = "8jQxxxx0WW6"; String ds = "aW60ImxxxxIj61ZbV"; String ps = "EBcjxxxxWxdF"; if ( args.length >= 4) { pk = args[0]; dn = args[1]; ds = args[2]; ps = args[3]; } String payload = pk + dn + ds + ps; ByteBuffer bbuffer = ByteBuffer.allocate(payload.length()); bbuffer.put(payload.getBytes()); // Your CRC class. CRC32 crc = new CRC32(); crc.update(bbuffer.array()); String enc = Long.toHexString(crc.getValue()).toUpperCase(); System.out.println("payload: " + payload); System.out.println("length: " + Integer.toString(payload.length())); System.out.println("crc32: " + enc); } } - Python reference implementation
import zlib pk = "a2xxxx8HZ" dn = "ouxxxxemo" ds = "GD4JauYxxxxsICazhIzb" ps = "4I3xxxxyF96" def Crc32Hash(input_data): crc32 = 0 crc32 = zlib.crc32(input_data, crc32) return format(crc32 & 0xFFFFFFFF, '08X') payload = pk + dn + ds + ps print "payload: ", payload print "length: ", len(payload) print "crc32: ", Crc32Hash(payload) - Device-side reference code
#define CHIP_CPU_BE #define dwPolynomial_BE 0xEDB88320UL // CRC32 Polynomial #define dwPolynomial 0x04C11DB7UL // CRC32 Polynomial #if defined(CHIP_CPU_BE) #define dwPolynomial dwPolynomial_BE #else #define dwPolynomial dwPolynomial_LE #endif #define CRC_INIT_VALUE 0xFFFFFFFFUL unsigned int calc_crc32(unsigned char *message) { int i, j; unsigned int byte, crc, mask; i = 0; crc = CRC_INIT_VALUE; while (message[i] != 0) { byte = message[i]; // Get next byte. crc = crc ^ byte; for (j = 7; j >= 0; j--) { // Do eight times. mask = -(crc & 1); crc = (crc >> 1) ^ (dwPolynomial_BE & mask); } i = i + 1; } return ~crc; }
Use the server-side tool
The server-side tool consists of two parts: device certificate distribution and device certificate management.
- Download the device certificate tool.
- Start the device certificate distribution service.
- Unzip the downloaded file and double-click server/http_server.exe to start the distribution service.
The distribution service starts successfully when the following message appears.
Waiting for client requestNote The current version is not a system service. Do not close the window after you start the service. - (Optional) Modify the port number.
By default, the distribution service uses port 8000. To change the port, run the following command. The example changes the port to 50000.
http_server.exe 50000
- Unzip the downloaded file and double-click server/http_server.exe to start the distribution service.
- Manage product batches and import device certificates.
- Double-click server/factory.exe to start the management tool.
- Click Add Device.
- Configure the product batch and product information. Click Select Device Identity File and select the device identity file that you downloaded from the IoT Platform console.
Note If the identity file contains the ProductSecret field, the program automatically reads the field and uses the value from the file.
- Click the Add Device button.
After the import is complete, a message that shows the import details appears.
- Query product information.
- Click Device Query and enter the name of the product to query in the DeviceName input box.
- Click Query.
The device details are displayed.
(Optional) Use the Node.js SDK to verify the server
The device certificate distribution tool provides a Node.js SDK reference implementation. You can use the Node.js SDK to verify that the link for the server to obtain device certificates works correctly.
Follow these steps to develop and run the sample code.
- Download the device certificate distribution tool.
In the client\NodeJS folder, you can view the Node.js SDK files. The files are described as follows.
- test.js: A sample file that calls devReqCert.js to obtain a device certificate.
- devReqCert.js: Provides the
req_dev_cert()andsend_burn_result_by_did()functions. The functions are described as follows.- req_dev_cert('ip',"pk",id,callback)
Requests a device certificate from a specified server. The parameters are described in the following table.
Parameter Type Description ip String The IP address or domain name of the server. pk String The product model for which the device requests identity information. This parameter corresponds to the ProductKey of the product on the Alibaba Cloud IoT Platform. id String The unique identifier of the device, such as a MAC address or serial number (SN). It must be unique to the device. - If you use the same ID to make a request, the server returns the same device certificate.
- If the ID value is null, the device requests a new identity.
callback function The callback function that is invoked after the server returns the device certificate. It is used to save the device certificate. You must implement this function yourself. - send_burn_result_by_did('ip',"pk","id")
Sends the result of the device identity write operation to a specified server. After the server receives the result from the client, the server changes the status of the device identity from Allocated to Written. The parameters are described in the following table.
Parameter Type Description ip String The IP address or domain name of the server. pk String The product model for which the device requests identity information. This parameter corresponds to the ProductKey of the product on the Alibaba Cloud IoT Platform. id String The unique identifier of the device, such as a MAC address or SN. It must be unique to the device. - If you use the same ID to make a request, the server returns the same device certificate.
- If the ID value is null, the device requests a new identity.
- req_dev_cert('ip',"pk",id,callback)
- Develop the sample code.
The sample code is based on the `test.js` file.
var http = require('http'); // Import the dependency on the HTTP library. var devReq = require('./devReqCert'); // Import the dependency on devReqCert. var did = null; // The following handler function is the processing function after the client receives the device certificate allocated by the server. // In this sample code, the device identity information is only printed. // In actual product production, the device identity information must be saved for persistence. function handler(devInfo) { var jsonObj = JSON.parse(devInfo); console.log("DevInfo:" + devInfo); } // The following statement calls req_dev_cert to obtain the device identity information. // "127.0.0.1" is the IP address of the server. In this test, the server and client are on the same PC, so the 127.0.0.1 address is used. // The parameter "a1RxxxxBm9" is the ProductKey for which the device requests an identity. // null indicates that the device does not have a unique identifier and requests a new device identity from the server. devReq.req_dev_cert('127.0.0.1',"a1RxxxxBm9",null, handler); // The following code sets the unique identifier of the device and requests the unique identifier of the device again. did = "123456"; devReq.req_dev_cert('127.0.0.1',"a1RxxxxBm9",did,handler); - Deploy the Node.js environment on the PC or client device where you run the code.
- Go to the `NodeJS` folder of the production line distribution tool and run node test.js.
If the output is similar to the following, the link for the server to obtain device certificates works correctly. `DeviceName`, `ProductKey`, `ProductSecret`, and `DeviceSecret` are the device certificate components that the Alibaba Cloud IoT Platform allocates to the device. `DeviceID` is the device identifier that is passed in when the device requests an identity.
Develop a client using the C SDK
You can use one of the following two methods to implement the function for a device to obtain identity information.
- On the production line, use a General-Purpose Input/Output (GPIO) pin of the device as an input interface. Pull the pin high or low. When the device powers on and detects that the GPIO pin is high or low, the device automatically connects to a fixed Wi-Fi access point (AP) and then requests a device certificate from the server. The server's IP address must be fixed.
- After the device powers on, check whether it has a device identity. If the device does not have identity information, it automatically connects to a fixed production line AP. You must define the AP's SSID and password. Then, you can use the C SDK provided by the device certificate distribution tool to request a device identity by calling
get_triple.
Follow these steps to develop a client based on the sample code.
- Download the device certificate distribution tool.
In the client\C-SDK folder, you can view the C SDK files. The files are described as follows.
- triple_burn.c: Stores the SDK code.
- triple_burn.h: A header file that contains the
send_req()andparse_data()functions. The functions are described as follows.- char* send_req(act, pk, did, const server_ip)
Requests a device certificate from a specified server or sends the result of the device certificate write operation. The parameters are described in the following table.
Parameter Type Description act Int - 0: The client requests a device identity from the server.
- 1: The client informs the server that the device identity was written successfully.
pk char * The product model for which the device requests identity information. This parameter corresponds to the ProductKey of the product on the Alibaba Cloud IoT Platform. did char * The unique identifier of the device, such as a MAC address or SN. Special cases:
- If you use the same ID to make a request, the server returns the same device certificate.
- The device does not have a unique identifier. You can pass an empty string, but use this option with caution because it may waste device certificates.
server_ip char * The IP address of the device where the server service is located. The device identity that is returned by the server is in JSON format. A NULL value indicates that the request for an identity failed.
- int parse_data(const data, pk, dn, ps, ds, did)
This function parses the JSON string that is returned from the server and obtains the ProductKey, ProductSecret, DeviceName, DeviceSecret, and DeviceID. You can modify this function to add other configuration information for each device on the server.
Parameter Type Description data char * The device certificate obtained from the server by the send_req()function.pk char * The product model of the device. This parameter corresponds to the ProductKey of the product on the Alibaba Cloud IoT Platform. dn char * The name of the device. This parameter corresponds to the DeviceName of the device on the Alibaba Cloud IoT Platform. ps char * This parameter corresponds to the ProductSecret of the device on the Alibaba Cloud IoT Platform. ds char * This parameter corresponds to the DeviceSecret of the device on the Alibaba Cloud IoT Platform. did char * The unique identifier of the device, such as a MAC address or SN. Special cases:
- If you use the same ID to make a request, the server returns the same device certificate.
- The device does not have a unique identifier. You can pass an empty string, but use this option with caution because it may waste device certificates.
server_ip char * The IP address of the device where the server service is located. The return values of this function are described as follows.
- 0: Parsing is successful.
- Non-zero: Invalid data.
- char* send_req(act, pk, did, const server_ip)
- Develop the
get_triple()function.The following steps show how to use the C SDK to obtain a device certificate for a device that has the IoT Platform SDK integrated. You can use these steps to develop your sample code.
- Ensure that the device correctly obtains an IP address through DHCP.
- Call
HAL_Wifi_Get_IP()to obtain the device's IP address. - Call
send_req()to obtain the device certificate.If no data is obtained, the request is automatically sent again. If data is still not obtained, you must implement the subsequent business logic as needed. - Call
parse_data()to parse the data.If the data is parsed successfully, you can obtain the device's ProductKey, ProductSecret, DeviceName, and DeviceSecret.The example only prints the device certificate, as shown in the log in the following code. When you develop your application, you must store this information in Flash or NVRAM.
static void get_triple(char* server_ip, char* productKey, char* deviceid){ char ip_addr[16] = {0}; char pk[PRODUCT_KEY_LEN] = {0}; char dn[DEVICE_NAME_LEN] = {0}; char ds[DEVICE_SECRET_LEN] = {0}; char ps[PRODUCT_SECRET_LEN] = {0}; char did[PRODUCT_SECRET_LEN] = {0}; HAL_Wifi_Get_IP(ip_addr, 0); if (strlen(ip_addr) > 5){ LOG("wifi_service_event ip=%s", ip_addr); char *response_payload = send_req(0, productKey, deviceid, server_ip); if (strlen(response_payload) == 0){ if (response_payload != NULL) HAL_Free(response_payload); response_payload = send_req(0, productKey, deviceid, server_ip); } if( response_payload != NULL && 0 == parse_data(response_payload, pk, dn, ps, ds, did)){ HAL_Free(response_payload); LOG("triple:pk=%s dn=%s ds=%s ps=%s did=%s", pk,dn,ds,ps,did); // write pk,dn,ds,ps to flash // send write success to server HAL_Free(send_req(1, productKey, did, server_ip)); } else { if (response_payload != NULL) HAL_Free(response_payload); } } - Call
send_req()again to inform the server that the device certificate has been saved successfully.
- Integrate the client SDK sample code.
The following integration is based on the released IoT Platform SDK. To obtain the IoT Platform SDK, see Get the SDK.
The following example is based on `living_platform`. If you develop based on other applications, you must adjust the paths accordingly.
- In Product/example/living_platfrom/living_platfrom.mk, add the triple_burn.c file.
- In the app_entry.c file, add
include triple_burn.h.#if defined(OTA_ENABLED) && defined(BUILD_AOS) #include "ota_service.h" #endif #include "triple_burn.h" // triple_burn.h is the header file. #include <aos/network.h> - Place get_triple in the app_entry.c file of the `living_platform` application.
- Refer to the following sample code to implement a call to
get_triple()inhandle_linkkey_cmd()to obtain the device certificate.For more code, see the client\C-SDK\app_entry.c file.static void handle_linkkey_cmd(char *pwbuf, int blen, int argc, char **argv) { if (argc == 1) { int len = 0; char product_key[PRODUCT_KEY_LEN + 1] = {0}; char product_secret[PRODUCT_SECRET_LEN + 1] = {0}; char device_name[DEVICE_NAME_LEN + 1] = {0}; char device_secret[DEVICE_SECRET_LEN + 1] = { 0 }; len = PRODUCT_KEY_LEN+1; aos_kv_get("linkkit_product_key", product_key, &len); len = PRODUCT_SECRET_LEN+1; aos_kv_get("linkkit_product_secret", product_secret, &len); len = DEVICE_NAME_LEN+1; aos_kv_get("linkkit_device_name", device_name, &len); len = DEVICE_SECRET_LEN+1; aos_kv_get("linkkit_device_secret", device_secret, &len); aos_cli_printf("Product Key=%s.\r\n", product_key); aos_cli_printf("Device Name=%s.\r\n", device_name); aos_cli_printf("Device Secret=%s.\r\n", device_secret); aos_cli_printf("Product Secret=%s.\r\n", product_secret); } else if (argc == 5) { aos_kv_set("linkkit_product_key", argv[1], strlen(argv[1]) + 1, 1); aos_kv_set("linkkit_device_name", argv[2], strlen(argv[2]) + 1, 1); aos_kv_set("linkkit_device_secret", argv[3], strlen(argv[3]) + 1, 1); aos_kv_set("linkkit_product_secret", argv[4], strlen(argv[4]) + 1, 1); aos_cli_printf("Done"); } else if (argc == 4){ get_triple(argv[1], argv[2], argv[3]); } else if (argc == 3){ get_triple(argv[1], argv[2], ""); } else { aos_cli_printf("Error: %d\r\n", __LINE__); return; } } - Configure the batch network provisioning feature for devices.
This feature allows Wi-Fi devices that do not have Wi-Fi hot spot information to automatically connect to a factory test router. For more information, see New SDK features.
- Compile the firmware and write it to the device.
- Test the sample code.
After you write the firmware that contains the preceding code to the device, you can enter the following commands in the serial terminal to test the firmware.
- Request a device certificate with a DeviceID
linkkey ServerIP productKey DID // ServerIP is the IP address of the server in the actual environment. productKey is the ProductKey of the product. // DID is the unique identifier of the device, such as a MAC address or serial number, that can uniquely identify the device. - Request a device certificate without a DeviceID (Use this option with caution because it may waste device certificates)
linkkey ServerIP productKey // At runtime, you must enter the IP address of the server in the actual environment for ServerIP. productKey is the ProductKey of your product.
If the device successfully retrieves data from the server, a log similar to the following is generated.
resp={"CRC32":3041429316,"ProductKey":"a1xxxxNW", "DeviceName":"ZTMxxxxxTUy", "DeviceSecret":"NmMzxxxxjE5", "ProductSecret":"Xmxxxxb9R","Status":"OK"}. - Request a device certificate with a DeviceID