Skip to content

Commit 4158871

Browse files
authored
Merge pull request #90 from arduino/secure_elements
misc: Add support for secure elements on MicroPython.
2 parents e034e2e + fb4dd6f commit 4158871

File tree

3 files changed

+35
-15
lines changed

3 files changed

+35
-15
lines changed

examples/example.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ def user_task(client, args):
6363
# ID, and the password is the secret key obtained from the IoT cloud when provisioning a device.
6464
client = ArduinoCloudClient(device_id=DEVICE_ID, username=DEVICE_ID, password=SECRET_KEY, sync_mode=args.sync)
6565

66-
# Alternatively, the client also supports key and certificate-based authentication. To use this
67-
# mode, set "keyfile" and "certfile", and the CA certificate (if any) in "ssl_params".
68-
# Furthermore, secure elements, which can be used to store the key and cert, are also supported.
69-
# To secure elements, set "use_hsm" to True in "ssl_params" and set the token's "pin" if any.
66+
# Alternatively, the client supports key and certificate-based authentication. To use this
67+
# mode, set "keyfile" and "certfile", and specify the CA certificate (if any) in "ssl_params".
68+
# Secure elements, which can be used to store the key and certificate, are also supported.
69+
# To use secure elements, provide the key and certificate URIs (in provider:token format) and
70+
# set the token's PIN (if applicable). For example:
7071
# client = ArduinoCloudClient(
7172
# device_id=DEVICE_ID,
7273
# ssl_params={
73-
# "use_hsm": True, "pin": "1234",
74-
# "keyfile": KEY_PATH, "certfile": CERT_PATH, "cafile": CA_PATH,
74+
# "pin": "1234", "keyfile": KEY_PATH, "certfile": CERT_PATH, "cafile": CA_PATH,
7575
# "verify_mode": ssl.CERT_REQUIRED, "server_hostname" : "iot.arduino.cc"
7676
# },
7777
# sync_mode=args.sync,

examples/micropython_basic.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
from secrets import DEVICE_ID
1919
from secrets import SECRET_KEY # noqa
2020

21-
KEY_PATH = "key.der"
22-
CERT_PATH = "cert.der"
21+
KEY_PATH = "key.der" # noqa
22+
CERT_PATH = "cert.der" # noqa
2323

2424

2525
def on_switch_changed(client, value):
@@ -76,13 +76,15 @@ def wifi_connect():
7676
# ID, and the password is the secret key obtained from the IoT cloud when provisioning a device.
7777
client = ArduinoCloudClient(device_id=DEVICE_ID, username=DEVICE_ID, password=SECRET_KEY, sync_mode=False)
7878

79-
# Alternatively, the client also supports key and certificate-based authentication. To use this
80-
# mode, set "keyfile" and "certfile", and the CA certificate (if any) in "ssl_params".
81-
# Note that for MicroPython, the key and cert files must be stored in DER format on the filesystem.
79+
# Alternatively, the client supports key and certificate-based authentication. To use this
80+
# mode, set "keyfile" and "certfile", and specify the CA certificate (if any) in "ssl_params".
81+
# Secure elements, which can be used to store the key and certificate, are also supported.
82+
# To use secure elements, provide the key and certificate URIs (in provider:token format) and
83+
# set the token's PIN (if applicable). For example:
8284
# client = ArduinoCloudClient(
8385
# device_id=DEVICE_ID,
8486
# ssl_params={
85-
# "keyfile": KEY_PATH, "certfile": CERT_PATH, "cadata": CADATA,
87+
# "pin": "1234", "keyfile": KEY_PATH, "certfile": CERT_PATH, "cadata": CADATA,
8688
# "verify_mode": ssl.CERT_REQUIRED, "server_hostname" : "iot.arduino.cc"
8789
# },
8890
# sync_mode=False,

src/arduino_iot_cloud/ussl.py

+21-3
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,21 @@
99
import ssl
1010
import sys
1111
import logging
12+
import binascii
1213

1314
pkcs11 = None
1415

1516
# Default engine and provider.
1617
_ENGINE_PATH = "/usr/lib/engines-3/libpkcs11.so"
1718
_MODULE_PATH = "/usr/lib/softhsm/libsofthsm2.so"
1819

20+
# Reference EC key for NXP's PlugNTrust
21+
_EC_REF_KEY = binascii.unhexlify(
22+
b"3041020100301306072a8648ce3d020106082a8648ce3d03010704273025"
23+
b"0201010420100000000000000000000000000000000000ffffffffa5a6b5"
24+
b"b6a5a6b5b61000"
25+
)
26+
1927

2028
def wrap_socket(sock, ssl_params={}):
2129
keyfile = ssl_params.get("keyfile", None)
@@ -25,9 +33,19 @@ def wrap_socket(sock, ssl_params={}):
2533
ciphers = ssl_params.get("ciphers", None)
2634
verify = ssl_params.get("verify_mode", ssl.CERT_NONE)
2735
hostname = ssl_params.get("server_hostname", None)
28-
use_hsm = ssl_params.get("use_hsm", False)
36+
micropython = sys.implementation.name == "micropython"
37+
38+
if keyfile is not None and "token" in keyfile and micropython:
39+
# Create a reference EC key for NXP EdgeLock device.
40+
objid = int(keyfile.split("=")[1], 16).to_bytes(4, "big")
41+
keyfile = _EC_REF_KEY[0:53] + objid + _EC_REF_KEY[57:]
42+
# Load the certificate from the secure element (when supported).
43+
# import cryptoki
44+
# with cryptoki.open() as token:
45+
# cert = token.read(0x65, 412)
2946

30-
if not use_hsm:
47+
if keyfile is None or "token" not in keyfile:
48+
# Use MicroPython/CPython SSL to wrap socket.
3149
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
3250
if hasattr(ctx, "set_default_verify_paths"):
3351
ctx.set_default_verify_paths()
@@ -39,7 +57,7 @@ def wrap_socket(sock, ssl_params={}):
3957
if ciphers is not None:
4058
ctx.set_ciphers(ciphers)
4159
if cafile is not None or cadata is not None:
42-
ctx.load_verify_locations(cafile, cadata)
60+
ctx.load_verify_locations(cafile=cafile, cadata=cadata)
4361
return ctx.wrap_socket(sock, server_hostname=hostname)
4462
else:
4563
# Use M2Crypto to load key and cert from HSM.

0 commit comments

Comments
 (0)