Skip to content

X.509 Device Identity

These functions create and hold the device’s cryptographic identity: an elliptic-curve key pair (secp256r1) and a self-signed certificate, stored in a reserved flash region. They survive reboots and application downloads, and the private key never leaves the chip.

The identity is what lets a cloud platform authenticate the device without a shared secret — see MQTT / MQTTS.

Install the library first — see Library. Every text parameter is a POINTER TO BYTE, passed with ADR().

FilenXPicoX509.compiled-library — 598 KB
TypePrecompiled library: no source, nothing to build
Exported functions8, listed below
BoardsnXPico W and nXPico M
RequiresNothing — the implementation is in the firmware; the library only declares it

Installing the library does not add code to your application: it declares functions that the runtime already carries. That is why it works on two different boards with one file, and why a board whose firmware lacks those functions rejects the download instead of failing silently.

Generates key and certificate. Asynchronous — returns immediately, the work takes about 450 ms.

FUNCTION x509GenerateDeviceCert : DINT
VAR_INPUT
pSubject : POINTER TO BYTE; (* e.g. ADR('CN=nxpico-01'); NULL = default *)
diValidityDays : DINT; (* ignored: fixed validity 2025-2035 *)
xForce : BOOL; (* TRUE = regenerate even if one exists *)
END_VAR
ReturnMeaning
10accepted, generation started — the only value returned

An invalid pSubject is reported later, as 2 in x509GetGenerateStatus().

diValidityDays is currently ignored: the certificate is always valid from 2025-01-01 to 2035-01-01.

Wait for completion with x509HasDeviceCert() or x509GetGenerateStatus(). Calling it again while generation is running is harmless — it returns 10. With xForce = FALSE and an identity already present it does nothing and the status becomes 0.

FUNCTION x509HasDeviceCert : BOOL

TRUE when a valid identity is in flash. The simplest way to know generation has finished.

FUNCTION x509GetGenerateStatus : DINT
ReturnMeaning
10generation in progress
0completed successfully
2pSubject is not a valid pointer
othererror code
FUNCTION x509GetDeviceCertLen : DINT

Length in bytes of the PEM certificate, 0 if absent. Typically 595.

Prints the whole certificate to the diagnostic log, delimited and ready to copy. This is the recommended way to extract the certificate for registration on a cloud platform.

FUNCTION x509DumpDeviceCert : DINT
ReturnMeaning
10accepted, printing follows immediately
1no certificate in flash — generate the identity first
[X509] ---- inizio certificato device (595 byte): copiare da qui ----
-----BEGIN CERTIFICATE-----
MIIB...
-----END CERTIFICATE-----
[X509] ---- fine certificato device ----

Copy everything between the two delimiters, -----BEGIN and -----END lines included.

Copies the PEM certificate into an application buffer.

FUNCTION x509GetDeviceCert : DINT
VAR_INPUT
pBuf : POINTER TO BYTE;
udiSize : UDINT; (* use SIZEOF(yourBuffer) *)
END_VAR
ReturnMeaning
0copied
15buffer too small
1no certificate in flash

Reads the certificate piecewise, to move it into small buffers or push it onto a socket.

FUNCTION x509GetDeviceCertChunk : DINT
VAR_INPUT
diOffset : DINT; (* from 0 upwards *)
pBuf : POINTER TO BYTE;
udiSize : UDINT;
END_VAR

Returns the number of bytes copied, 0 when there is nothing left.

Generates a Certificate Signing Request, to have the certificate signed by a CA.

FUNCTION x509GenerateCsr : DINT
VAR_INPUT
pSubject : POINTER TO BYTE;
pBuf : POINTER TO BYTE;
udiSize : UDINT;
END_VAR

Returns 0 if the CSR was written to the buffer, 1 if the buffer is too small. Requires an identity to already exist (without one it also returns 1) — the CSR is signed with the device’s private key.

VAR
xGen, xGenPrev, xDump, xDumpPrev : BOOL;
diRes, diStatus, diCertLen : DINT;
xHasCert : BOOL;
END_VAR
(* generation: once in the life of the device *)
IF xGen AND NOT xGenPrev THEN
diRes := x509GenerateDeviceCert(ADR('CN=nxpico-01'), 3650, FALSE);
END_IF
xGenPrev := xGen;
xHasCert := x509HasDeviceCert();
diStatus := x509GetGenerateStatus();
diCertLen := x509GetDeviceCertLen();
(* print it to the log, to register it on the platform *)
IF xDump AND NOT xDumpPrev THEN
diRes := x509DumpDeviceCert();
END_IF
xDumpPrev := xDump;

The log reports each phase:

[X509] fase 1/3: keygen EC secp256r1...
[X509] fase 1/3 keygen -> 0 (219 ms)
[X509] fase 2/3 cert -> 0 (224 ms)
[X509] fase 3/3 save -> 0 (10 ms) has=1