diff --git a/examples/example.py b/examples/example.py index 00823b8..b91867f 100644 --- a/examples/example.py +++ b/examples/example.py @@ -63,15 +63,15 @@ def user_task(client, args): # ID, and the password is the secret key obtained from the IoT cloud when provisioning a device. client = ArduinoCloudClient(device_id=DEVICE_ID, username=DEVICE_ID, password=SECRET_KEY, sync_mode=args.sync) - # Alternatively, the client also supports key and certificate-based authentication. To use this - # mode, set "keyfile" and "certfile", and the CA certificate (if any) in "ssl_params". - # Furthermore, secure elements, which can be used to store the key and cert, are also supported. - # To secure elements, set "use_hsm" to True in "ssl_params" and set the token's "pin" if any. + # Alternatively, the client supports key and certificate-based authentication. To use this + # mode, set "keyfile" and "certfile", and specify the CA certificate (if any) in "ssl_params". + # Secure elements, which can be used to store the key and certificate, are also supported. + # To use secure elements, provide the key and certificate URIs (in provider:token format) and + # set the token's PIN (if applicable). For example: # client = ArduinoCloudClient( # device_id=DEVICE_ID, # ssl_params={ - # "use_hsm": True, "pin": "1234", - # "keyfile": KEY_PATH, "certfile": CERT_PATH, "cafile": CA_PATH, + # "pin": "1234", "keyfile": KEY_PATH, "certfile": CERT_PATH, "cafile": CA_PATH, # "verify_mode": ssl.CERT_REQUIRED, "server_hostname" : "iot.arduino.cc" # }, # sync_mode=args.sync, diff --git a/examples/micropython_basic.py b/examples/micropython_basic.py index b97cea8..7bfafce 100644 --- a/examples/micropython_basic.py +++ b/examples/micropython_basic.py @@ -18,8 +18,8 @@ from secrets import DEVICE_ID from secrets import SECRET_KEY # noqa -KEY_PATH = "key.der" -CERT_PATH = "cert.der" +KEY_PATH = "key.der" # noqa +CERT_PATH = "cert.der" # noqa def on_switch_changed(client, value): @@ -76,13 +76,15 @@ def wifi_connect(): # ID, and the password is the secret key obtained from the IoT cloud when provisioning a device. client = ArduinoCloudClient(device_id=DEVICE_ID, username=DEVICE_ID, password=SECRET_KEY, sync_mode=False) - # Alternatively, the client also supports key and certificate-based authentication. To use this - # mode, set "keyfile" and "certfile", and the CA certificate (if any) in "ssl_params". - # Note that for MicroPython, the key and cert files must be stored in DER format on the filesystem. + # Alternatively, the client supports key and certificate-based authentication. To use this + # mode, set "keyfile" and "certfile", and specify the CA certificate (if any) in "ssl_params". + # Secure elements, which can be used to store the key and certificate, are also supported. + # To use secure elements, provide the key and certificate URIs (in provider:token format) and + # set the token's PIN (if applicable). For example: # client = ArduinoCloudClient( # device_id=DEVICE_ID, # ssl_params={ - # "keyfile": KEY_PATH, "certfile": CERT_PATH, "cadata": CADATA, + # "pin": "1234", "keyfile": KEY_PATH, "certfile": CERT_PATH, "cadata": CADATA, # "verify_mode": ssl.CERT_REQUIRED, "server_hostname" : "iot.arduino.cc" # }, # sync_mode=False, diff --git a/src/arduino_iot_cloud/ussl.py b/src/arduino_iot_cloud/ussl.py index f0c51af..058532a 100644 --- a/src/arduino_iot_cloud/ussl.py +++ b/src/arduino_iot_cloud/ussl.py @@ -9,6 +9,7 @@ import ssl import sys import logging +import binascii pkcs11 = None @@ -16,6 +17,13 @@ _ENGINE_PATH = "/usr/lib/engines-3/libpkcs11.so" _MODULE_PATH = "/usr/lib/softhsm/libsofthsm2.so" +# Reference EC key for NXP's PlugNTrust +_EC_REF_KEY = binascii.unhexlify( + b"3041020100301306072a8648ce3d020106082a8648ce3d03010704273025" + b"0201010420100000000000000000000000000000000000ffffffffa5a6b5" + b"b6a5a6b5b61000" +) + def wrap_socket(sock, ssl_params={}): keyfile = ssl_params.get("keyfile", None) @@ -25,9 +33,19 @@ def wrap_socket(sock, ssl_params={}): ciphers = ssl_params.get("ciphers", None) verify = ssl_params.get("verify_mode", ssl.CERT_NONE) hostname = ssl_params.get("server_hostname", None) - use_hsm = ssl_params.get("use_hsm", False) + micropython = sys.implementation.name == "micropython" + + if keyfile is not None and "token" in keyfile and micropython: + # Create a reference EC key for NXP EdgeLock device. + objid = int(keyfile.split("=")[1], 16).to_bytes(4, "big") + keyfile = _EC_REF_KEY[0:53] + objid + _EC_REF_KEY[57:] + # Load the certificate from the secure element (when supported). + # import cryptoki + # with cryptoki.open() as token: + # cert = token.read(0x65, 412) - if not use_hsm: + if keyfile is None or "token" not in keyfile: + # Use MicroPython/CPython SSL to wrap socket. ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) if hasattr(ctx, "set_default_verify_paths"): ctx.set_default_verify_paths() @@ -39,7 +57,7 @@ def wrap_socket(sock, ssl_params={}): if ciphers is not None: ctx.set_ciphers(ciphers) if cafile is not None or cadata is not None: - ctx.load_verify_locations(cafile, cadata) + ctx.load_verify_locations(cafile=cafile, cadata=cadata) return ctx.wrap_socket(sock, server_hostname=hostname) else: # Use M2Crypto to load key and cert from HSM.