platform: cznic: turris-omnia-mcu: Add support for digital message signing via keyctl
Subsystems (2)
Marek Behún
maintainerRFC PATCH 1/1 platform: cznic: turris-omnia-mcu: Add support for digital message signing via keyctl
Add support for digital message signing with private key stored in the MCU. Boards with MKL MCUs have a NIST256p ECDSA private key created when manufactured. The private key is not readable from the MCU, but MCU allows for signing messages with it and retrieving the public key.
This is exposed to userspace via the keyctl API. The module registers key type "turris-omnia-mcu", and on device probe, if the board supports this feature, it allocates the keyring ".turris-omnia-mcu-keys" with one key.
In userspace, the user can look at /proc/keys or list the keyring:
$ cat /proc/keys 0a3b7cd3 ... keyring .turris-omnia-mcu-keys: 1 3caf0b1a ... turris-om Turris Omnia SN 0000000A1000023 MCU ECDSA k...
$ keyctl rlist %:.turris-omnia-mcu-keys 1018104602
To get public key:
$ keyctl read 1018104602 33 bytes of data in key: 025d9108 1fb538ae 8435c88b b4379171 d6b158a9 55751b91 1d23e6a9 d017f4b2 1c
To sign a message:
$ dd if=/dev/urandom of=msg_to_sign bs=32 count=1 $ keyctl pkey_sign 1018104602 0 msg_to_sign >signature
The key and keyring are dropped when the driver is unbound from the device.
The keyring and key are created with only the VIEW, READ and SEARCH permissions for userspace - it is impossible to link / unlink / move the key, set its attributes, or unlink the keyring from userspace.
I found one thing not possible to prevent without changing code in security/keys: the userspace can create another key of type "turris-omnia-mcu" in another keyring, for example:
$ echo | keyctl padd turris-omnia-mcu TEST @u 972416162
Nonetheless the driver is written so that using this invalid key that shouldn't have been create at all will return -EIO:
$ keyctl pkey_query 972416162 0 keyctl_pkey_query: I/O error $ keyctl pkey_sign 972416162 0 msg_to_sign >signature keyctl_pkey_query: I/O error
---
Hi Herbert et al.,
this patch depends on patches in soc/soc.git.
I would like to get your thoughts on the following:
- should this driver create the special ".turris-omnia-mcu-keys" keyring, as it does in this RFC, or should it put the key into an existing keyring, for example user specific (root) keyring? Should it allow changing the keyring?
- should this driver prohibit changing owner of the key and other attributes, as it does in this RFC, or should it allow giving access to the key to other users?
Marek
--- drivers/platform/cznic/Kconfig | 4 + drivers/platform/cznic/Makefile | 1 + .../platform/cznic/turris-omnia-mcu-base.c | 30 +- .../platform/cznic/turris-omnia-mcu-keyctl.c | 294 ++++++++++++++++++ drivers/platform/cznic/turris-omnia-mcu.h | 15 + 5 files changed, 342 insertions(+), 2 deletions(-) create mode 100644 drivers/platform/cznic/turris-omnia-mcu-keyctl.c
drivers/platform/cznic/Kconfig +4 -0
@@ -21,6 +21,8 @@ config TURRIS_OMNIA_MCU select GPIOLIB select GPIOLIB_IRQCHIP select HW_RANDOM + select KEYS + select ASYMMETRIC_KEY_TYPE select RTC_CLASS select WATCHDOG_CORE help
@@ -31,6 +33,8 @@ config TURRIS_OMNIA_MCU disabled) and the ability to configure wake up from this mode (via rtcwake) - true random number generator (if available on the MCU) + - ECDSA message signing with board private key (if available on the + MCU) - MCU watchdog - GPIO pins - to get front button press events (the front button can be
drivers/platform/cznic/Makefile +1 -0
@@ -3,6 +3,7 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o turris-omnia-mcu-y := turris-omnia-mcu-base.o turris-omnia-mcu-y += turris-omnia-mcu-gpio.o +turris-omnia-mcu-y += turris-omnia-mcu-keyctl.o turris-omnia-mcu-y += turris-omnia-mcu-sys-off-wakeup.o turris-omnia-mcu-y += turris-omnia-mcu-trng.o turris-omnia-mcu-y += turris-omnia-mcu-watchdog.o
drivers/platform/cznic/turris-omnia-mcu-base.c +28 -2
@@ -385,7 +385,11 @@ static int omnia_mcu_probe(struct i2c_client *client)if (err)return err; -return omnia_mcu_register_trng (mcu); + err =omnia_mcu_register_trng (mcu); +if (err) +return err; + +return omnia_mcu_register_keyctl (mcu); }static const struct of_device_id of_omnia_mcu_match[] = {
@@ -401,7 +405,29 @@ static struct i2c_driver omnia_mcu_driver = { .dev_groups = omnia_mcu_groups, }, }; -module_i2c_driver (omnia_mcu_driver); + +static int __init omnia_mcu_driver_init (void ) +{ +int err; + + err =omnia_mcu_keyctl_init (); +if (err) +return err; + + err =i2c_add_driver (&omnia_mcu_driver); +if (err) +omnia_mcu_keyctl_exit (); + +return err; +} +module_init (omnia_mcu_driver_init); + +static void __exit omnia_mcu_driver_exit(void) +{ +i2c_del_driver (&omnia_mcu_driver); +omnia_mcu_keyctl_exit (); +} +module_exit (omnia_mcu_driver_exit);MODULE_AUTHOR ("Marek Behun <[email protected]>" );MODULE_DESCRIPTION ("CZ.NIC's Turris Omnia MCU" );
drivers/platform/cznic/turris-omnia-mcu-keyctl.c new file +294 -0
294 lines not on this page · raw message
drivers/platform/cznic/turris-omnia-mcu.h +15 -0
@@ -20,6 +20,9 @@#include <asm/byteorder.h> #include <asm/unaligned.h> +#define OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN (1 + 32) +#define OMNIA_MCU_CRYPTO_SIGNATURE_LEN 64 +struct i2c_client ;struct rtc_device ;
@@ -32,6 +35,7 @@ struct omnia_mcu {u64 board_serial_number;u8 board_first_mac[ETH_ALEN ];u8 board_revision; +u8 board_public_key[OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN ];/* GPIO chip */ struct gpio_chip gc;
@@ -53,6 +57,13 @@ struct omnia_mcu {/* true random number generator */ struct hwrng trng;struct completion trng_entropy_ready; + +/* MCU ECDSA message signing via keyctl */ +struct completion msg_signed_completion; +struct mutex sign_lock; +bool sign_requested; +u8 signature[OMNIA_MCU_CRYPTO_SIGNATURE_LEN ]; +int sign_err; }; int omnia_cmd_write_read(const struct i2c_client *client,
@@ -187,8 +198,12 @@ extern const struct attribute_group omnia_mcu_gpio_group;extern const struct attribute_group omnia_mcu_poweroff_group;int omnia_mcu_register_gpiochip (struct omnia_mcu *mcu); +int omnia_mcu_register_keyctl (struct omnia_mcu *mcu);int omnia_mcu_register_sys_off_and_wakeup (struct omnia_mcu *mcu);int omnia_mcu_register_trng (struct omnia_mcu *mcu);int omnia_mcu_register_watchdog (struct omnia_mcu *mcu); +int omnia_mcu_keyctl_init (void ); +void omnia_mcu_keyctl_exit (void ); +#endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.44.2