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