1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * CZ.NIC's Turris Omnia MCU ECDSA message signing via keyctl 4 * 5 * 2025 by Marek Behún <kabel@kernel.org> 6 */ 7 8 #include <crypto/sha2.h> 9 #include <linux/cleanup.h> 10 #include <linux/completion.h> 11 #include <linux/device.h> 12 #include <linux/err.h> 13 #include <linux/i2c.h> 14 #include <linux/interrupt.h> 15 #include <linux/key.h> 16 #include <linux/mutex.h> 17 #include <linux/string.h> 18 #include <linux/types.h> 19 20 #include <linux/turris-omnia-mcu-interface.h> 21 #include <linux/turris-signing-key.h> 22 #include "turris-omnia-mcu.h" 23 24 static irqreturn_t omnia_msg_signed_irq_handler(int irq, void *dev_id) 25 { 26 u8 reply[1 + OMNIA_MCU_CRYPTO_SIGNATURE_LEN]; 27 struct omnia_mcu *mcu = dev_id; 28 int err; 29 30 err = omnia_cmd_read(mcu->client, OMNIA_CMD_CRYPTO_COLLECT_SIGNATURE, 31 reply, sizeof(reply)); 32 if (!err && reply[0] != OMNIA_MCU_CRYPTO_SIGNATURE_LEN) 33 err = -EIO; 34 35 guard(mutex)(&mcu->sign_lock); 36 37 if (mcu->sign_requested) { 38 mcu->sign_err = err; 39 if (!err) 40 memcpy(mcu->signature, &reply[1], 41 OMNIA_MCU_CRYPTO_SIGNATURE_LEN); 42 mcu->sign_requested = false; 43 complete(&mcu->msg_signed); 44 } 45 46 return IRQ_HANDLED; 47 } 48 49 static int omnia_mcu_sign(const struct key *key, const void *msg, 50 void *signature) 51 { 52 struct omnia_mcu *mcu = dev_get_drvdata(turris_signing_key_get_dev(key)); 53 u8 cmd[1 + SHA256_DIGEST_SIZE], reply; 54 int err; 55 56 scoped_guard(mutex, &mcu->sign_lock) { 57 if (mcu->sign_requested) 58 return -EBUSY; 59 60 cmd[0] = OMNIA_CMD_CRYPTO_SIGN_MESSAGE; 61 memcpy(&cmd[1], msg, SHA256_DIGEST_SIZE); 62 63 err = omnia_cmd_write_read(mcu->client, cmd, sizeof(cmd), 64 &reply, 1); 65 if (err) 66 return err; 67 68 if (!reply) 69 return -EBUSY; 70 71 mcu->sign_requested = true; 72 } 73 74 if (wait_for_completion_interruptible(&mcu->msg_signed)) 75 return -EINTR; 76 77 guard(mutex)(&mcu->sign_lock); 78 79 if (mcu->sign_err) 80 return mcu->sign_err; 81 82 memcpy(signature, mcu->signature, OMNIA_MCU_CRYPTO_SIGNATURE_LEN); 83 84 /* forget the signature, for security */ 85 memzero_explicit(mcu->signature, sizeof(mcu->signature)); 86 87 return OMNIA_MCU_CRYPTO_SIGNATURE_LEN; 88 } 89 90 static const void *omnia_mcu_get_public_key(const struct key *key) 91 { 92 struct omnia_mcu *mcu = dev_get_drvdata(turris_signing_key_get_dev(key)); 93 94 return mcu->board_public_key; 95 } 96 97 static const struct turris_signing_key_subtype omnia_signing_key_subtype = { 98 .key_size = 256, 99 .data_size = SHA256_DIGEST_SIZE, 100 .sig_size = OMNIA_MCU_CRYPTO_SIGNATURE_LEN, 101 .public_key_size = OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN, 102 .hash_algo = "sha256", 103 .get_public_key = omnia_mcu_get_public_key, 104 .sign = omnia_mcu_sign, 105 }; 106 107 static int omnia_mcu_read_public_key(struct omnia_mcu *mcu) 108 { 109 u8 reply[1 + OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN]; 110 int err; 111 112 err = omnia_cmd_read(mcu->client, OMNIA_CMD_CRYPTO_GET_PUBLIC_KEY, 113 reply, sizeof(reply)); 114 if (err) 115 return err; 116 117 if (reply[0] != OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN) 118 return -EIO; 119 120 memcpy(mcu->board_public_key, &reply[1], 121 OMNIA_MCU_CRYPTO_PUBLIC_KEY_LEN); 122 123 return 0; 124 } 125 126 int omnia_mcu_register_keyctl(struct omnia_mcu *mcu) 127 { 128 struct device *dev = &mcu->client->dev; 129 char desc[48]; 130 int err; 131 132 if (!(mcu->features & OMNIA_FEAT_CRYPTO)) 133 return 0; 134 135 err = omnia_mcu_read_public_key(mcu); 136 if (err) 137 return dev_err_probe(dev, err, 138 "Cannot read board public key\n"); 139 140 err = devm_mutex_init(dev, &mcu->sign_lock); 141 if (err) 142 return err; 143 144 init_completion(&mcu->msg_signed); 145 146 err = omnia_mcu_request_irq(mcu, OMNIA_INT_MESSAGE_SIGNED, 147 omnia_msg_signed_irq_handler, 148 "turris-omnia-mcu-keyctl"); 149 if (err) 150 return dev_err_probe(dev, err, 151 "Cannot request MESSAGE_SIGNED IRQ\n"); 152 153 sprintf(desc, "Turris Omnia SN %016llX MCU ECDSA key", 154 mcu->board_serial_number); 155 156 err = devm_turris_signing_key_create(dev, &omnia_signing_key_subtype, 157 desc); 158 if (err) 159 return dev_err_probe(dev, err, "Cannot create signing key\n"); 160 161 return 0; 162 } 163