Skip to content

Commit 5011e77

Browse files
committed
ussl: Add support for sign callback on MicroPython.
Signed-off-by: iabdalkader <[email protected]>
1 parent eae80d2 commit 5011e77

File tree

1 file changed

+63
-15
lines changed

1 file changed

+63
-15
lines changed

src/arduino_iot_cloud/ussl.py

+63-15
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,56 @@
99
import ssl
1010
import sys
1111
import logging
12-
import binascii
12+
try:
13+
from micropython import const
14+
except (ImportError, AttributeError):
15+
def const(x):
16+
return x
1317

1418
pkcs11 = None
19+
se_dev = None
1520

1621
# Default engine and provider.
1722
_ENGINE_PATH = "/usr/lib/engines-3/libpkcs11.so"
1823
_MODULE_PATH = "/usr/lib/softhsm/libsofthsm2.so"
1924

20-
# Reference EC key for NXP's PlugNTrust
21-
_EC_REF_KEY = binascii.unhexlify(
22-
b"3041020100301306072a8648ce3d020106082a8648ce3d03010704273025"
23-
b"0201010420100000000000000000000000000000000000ffffffffa5a6b5"
24-
b"b6a5a6b5b61000"
25+
# Reference EC key for the SE.
26+
_EC_REF_KEY = const(
27+
b"\x30\x41\x02\x01\x00\x30\x13\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01"
28+
b"\x06\x08\x2A\x86\x48\xCE\x3D\x03\x01\x07\x04\x27\x30\x25\x02\x01"
29+
b"\x01\x04\x20\xA5\xA6\xB5\xB6\xA5\xA6\xB5\xB6\x00\x00\x00\x00\x00"
30+
b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF"
31+
b"\xFF\xFF\xFF"
2532
)
2633

2734

35+
def log_level_enabled(level):
36+
return logging.getLogger().isEnabledFor(level)
37+
38+
39+
def ecdsa_sign_callback(key, data):
40+
if log_level_enabled(logging.DEBUG):
41+
key_hex = "".join("%02X" % b for b in key)
42+
logging.debug(f"ecdsa_sign_callback key:{key_hex}")
43+
44+
if key[0:8] != b"\xA5\xA6\xB5\xB6\xA5\xA6\xB5\xB6":
45+
if log_level_enabled(logging.DEBUG):
46+
logging.debug("ecdsa_sign_callback falling back to default sign")
47+
return None
48+
49+
obj_id = int.from_bytes(key[-4:], "big")
50+
if log_level_enabled(logging.DEBUG):
51+
logging.debug(f"ecdsa_sign_callback oid: 0x{obj_id:02X}")
52+
53+
# Sign data on SE using reference key object id.
54+
sig = se_dev.sign(obj_id, data)
55+
if log_level_enabled(logging.DEBUG):
56+
sig_hex = "".join("%02X" % b for b in sig)
57+
logging.debug(f"ecdsa_sign_callback sig: {sig_hex}")
58+
logging.info("Signed using secure element")
59+
return sig
60+
61+
2862
def wrap_socket(sock, ssl_params={}):
2963
keyfile = ssl_params.get("keyfile", None)
3064
certfile = ssl_params.get("certfile", None)
@@ -33,16 +67,27 @@ def wrap_socket(sock, ssl_params={}):
3367
ciphers = ssl_params.get("ciphers", None)
3468
verify = ssl_params.get("verify_mode", ssl.CERT_NONE)
3569
hostname = ssl_params.get("server_hostname", None)
36-
micropython = sys.implementation.name == "micropython"
3770

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)
71+
se_key_token = keyfile is not None and "token" in keyfile
72+
se_crt_token = certfile is not None and "token" in certfile
73+
sys_micropython = sys.implementation.name == "micropython"
74+
75+
if sys_micropython and (se_key_token or se_crt_token):
76+
import se05x
77+
78+
# Create and initialize SE05x device.
79+
global se_dev
80+
if se_dev is None:
81+
se_dev = se05x.SE05X()
82+
83+
if se_key_token:
84+
# Create a reference key for the secure element.
85+
obj_id = int(keyfile.split("=")[1], 16)
86+
keyfile = _EC_REF_KEY[0:-4] + obj_id.to_bytes(4, "big")
87+
88+
if se_crt_token:
89+
# Load the certificate from the secure element.
90+
certfile = se_dev.read(0x65, 412)
4691

4792
if keyfile is None or "token" not in keyfile:
4893
# Use MicroPython/CPython SSL to wrap socket.
@@ -58,6 +103,9 @@ def wrap_socket(sock, ssl_params={}):
58103
ctx.set_ciphers(ciphers)
59104
if cafile is not None or cadata is not None:
60105
ctx.load_verify_locations(cafile=cafile, cadata=cadata)
106+
if sys_micropython and se_key_token:
107+
# Set alternate ECDSA sign function.
108+
ctx._context.ecdsa_sign_callback = ecdsa_sign_callback
61109
return ctx.wrap_socket(sock, server_hostname=hostname)
62110
else:
63111
# Use M2Crypto to load key and cert from HSM.

0 commit comments

Comments
 (0)