Skip to content

x509gen

Module: x509gen
Source: cmodules/nxpico/mod_x509gen.c
Depends on: mbedTLS (bundled with MicroPython)

import x509gen

x509gen exposes mbedTLS cryptographic primitives directly to MicroPython, allowing the nXPico M to generate key pairs and X.509 certificates entirely on-device — no PC, no OpenSSL, no external CA required at provisioning time.

The typical use case is device identity for mutual TLS (mTLS): each device generates its own unique key pair and a certificate that identifies it to a broker or server. The private key never leaves the device — it is generated on-chip and stored directly in the nRF9151 secure storage via the modem module.

Self-signed — the device signs its own certificate. No external CA is involved. Suitable when the server trusts individual device certificates directly (e.g. AWS IoT just-in-time registration, or a private broker with a known device list).

generate_rsa_keypair() / generate_ec_keypair()
generate_self_signed_cert()
modem.write_certificate() ← cert + key stored in nRF9151

CSR — the device generates a key pair and a Certificate Signing Request, which is sent to a CA for signing. The signed certificate is then written back to the device. Required when a PKI hierarchy must be maintained.

generate_rsa_keypair() / generate_ec_keypair()
generate_csr() ← send to CA
receive signed cert from CA
modem.write_certificate()
RSA-2048EC secp256r1
Generation time on RP235010–30 s< 1 s
Key sizelargersmaller
Compatibilityuniversalbroad (TLS 1.2+)

Use EC when provisioning speed matters or when key size in the modem storage is a concern. Use RSA when the target server or CA requires it.


priv, pub = x509gen.generate_rsa_keypair(bits=2048)

Generate an RSA key pair.

ParameterTypeDefaultDescription
bitsint2048Key size in bits. Accepted range: 1024 – 4096.

Returns (private_key_pem, public_key_pem) as PEM strings.
Raises ValueError if bits is outside the accepted range.


priv, pub = x509gen.generate_ec_keypair(curve_name="secp256r1")

Generate an Elliptic Curve key pair.

ParameterTypeDefaultDescription
curve_namestr"secp256r1"Curve identifier.

Supported curves: "secp256r1", "secp384r1", "secp521r1".

Returns (private_key_pem, public_key_pem) as PEM strings.
Raises ValueError for unsupported curve names.


cert = x509gen.generate_self_signed_cert(
private_key_pem,
subject="CN=RP2350-Device,O=Embedded",
serial=1,
not_before="20250101000000",
not_after="20350101000000",
is_ca=False,
key_usage=0,
md_alg="sha256",
)

Generate and sign a self-signed X.509 certificate.

ParameterTypeDefaultDescription
private_key_pemstrPEM-encoded private key (RSA or EC).
subjectstr"CN=RP2350-Device,O=Embedded"Distinguished Name in CN=…,O=…,C=… format.
serialint1Certificate serial number.
not_beforestr"20250101000000"Validity start — format YYYYMMDDHHMMSS.
not_afterstr"20350101000000"Validity end — format YYYYMMDDHHMMSS.
is_caboolFalseSet to True to mark the certificate as a CA.
key_usageint0Bitmask of KU_* constants (see below). 0 = no constraints.
md_algstr"sha256"Signature hash: "sha256", "sha384", or "sha512".

Returns the certificate as a PEM string.


csr = x509gen.generate_csr(
private_key_pem,
subject="CN=RP2350-Device,O=Embedded",
md_alg="sha256",
)

Generate a Certificate Signing Request (CSR) to be signed by an external CA.

ParameterTypeDefaultDescription
private_key_pemstrPEM-encoded private key.
subjectstr"CN=RP2350-Device,O=Embedded"Distinguished Name.
md_algstr"sha256"Hash algorithm.

Returns the CSR as a PEM string (-----BEGIN CERTIFICATE REQUEST-----).


Use these constants as a bitmask for the key_usage parameter of generate_self_signed_cert.

ConstantMeaning
x509gen.KU_DIGITAL_SIGNATUREDigital signature
x509gen.KU_KEY_ENCIPHERMENTKey encipherment
x509gen.KU_DATA_ENCIPHERMENTData encipherment
x509gen.KU_KEY_AGREEMENTKey agreement
x509gen.KU_KEY_CERT_SIGNCertificate signing (CA only)
x509gen.KU_CRL_SIGNCRL signing (CA only)
ku = x509gen.KU_DIGITAL_SIGNATURE | x509gen.KU_KEY_ENCIPHERMENT
cert = x509gen.generate_self_signed_cert(priv, key_usage=ku)

Full example — generate and store a device certificate

Section titled “Full example — generate and store a device certificate”

Generate a self-signed certificate using the RP2350 unique ID as the device identifier, then write it and its private key to the modem’s secure storage.

import machine
import x509gen
from modem import Modem
def create_and_provision_cert(sec_tag: int = 1):
uid = machine.unique_id()
serial = ''.join('{:02X}'.format(b) for b in uid)
subject = f"CN=rp2350-{serial},O=neXo,C=IT"
print("[x509gen] Generating RSA-2048 key pair (may take ~30 s)...")
priv, _pub = x509gen.generate_rsa_keypair(2048)
print("[x509gen] Signing certificate...")
cert = x509gen.generate_self_signed_cert(
priv,
subject=subject,
not_before="20250101000000",
not_after="20350101000000",
is_ca=False,
md_alg="sha256",
)
m = Modem()
m.CFUN(4) # flight mode required before writing credentials
m.write_certificate(sec_tag, 1, cert) # cert_type=1: client certificate
m.write_certificate(sec_tag, 2, priv) # cert_type=2: client private key
m.CFUN(1)
print(f"[x509gen] Certificate and key stored at sec_tag={sec_tag}")
return cert, priv
cert_pem, priv_pem = create_and_provision_cert(sec_tag=1)