Skip to content

Commit 1d4eada

Browse files
committed
Merge tag 'mvebu-drivers-5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu into arm/drivers
mvebu drivers for 5.9 (part 1) For firmware on the Turris MOX (Armada 3720 based board), add support ECDSA signatures via debugfs. * tag 'mvebu-drivers-5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/gclement/mvebu: firmware: turris-mox-rwtm: add debugfs documentation firmware: turris-mox-rwtm: support ECDSA signatures via debugfs Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 1851774 + e6e57b6 commit 1d4eada

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
What: /sys/kernel/debug/turris-mox-rwtm/do_sign
2+
Date: Jun 2020
3+
KernelVersion: 5.8
4+
Contact: Marek Behún <[email protected]>
5+
Description: (W) Message to sign with the ECDSA private key stored in
6+
device's OTP. The message must be exactly 64 bytes (since
7+
this is intended for SHA-512 hashes).
8+
(R) The resulting signature, 136 bytes. This contains the R and
9+
S values of the ECDSA signature, both in big-endian format.

drivers/firmware/turris-mox-rwtm.c

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <linux/armada-37xx-rwtm-mailbox.h>
99
#include <linux/completion.h>
10+
#include <linux/debugfs.h>
1011
#include <linux/dma-mapping.h>
1112
#include <linux/hw_random.h>
1213
#include <linux/mailbox_client.h>
@@ -69,6 +70,18 @@ struct mox_rwtm {
6970
/* public key burned in eFuse */
7071
int has_pubkey;
7172
u8 pubkey[135];
73+
74+
#ifdef CONFIG_DEBUG_FS
75+
/*
76+
* Signature process. This is currently done via debugfs, because it
77+
* does not conform to the sysfs standard "one file per attribute".
78+
* It should be rewritten via crypto API once akcipher API is available
79+
* from userspace.
80+
*/
81+
struct dentry *debugfs_root;
82+
u32 last_sig[34];
83+
int last_sig_done;
84+
#endif
7285
};
7386

7487
struct mox_kobject {
@@ -279,6 +292,152 @@ static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
279292
return ret;
280293
}
281294

295+
#ifdef CONFIG_DEBUG_FS
296+
static int rwtm_debug_open(struct inode *inode, struct file *file)
297+
{
298+
file->private_data = inode->i_private;
299+
300+
return nonseekable_open(inode, file);
301+
}
302+
303+
static ssize_t do_sign_read(struct file *file, char __user *buf, size_t len,
304+
loff_t *ppos)
305+
{
306+
struct mox_rwtm *rwtm = file->private_data;
307+
ssize_t ret;
308+
309+
/* only allow one read, of 136 bytes, from position 0 */
310+
if (*ppos != 0)
311+
return 0;
312+
313+
if (len < 136)
314+
return -EINVAL;
315+
316+
if (!rwtm->last_sig_done)
317+
return -ENODATA;
318+
319+
/* 2 arrays of 17 32-bit words are 136 bytes */
320+
ret = simple_read_from_buffer(buf, len, ppos, rwtm->last_sig, 136);
321+
rwtm->last_sig_done = 0;
322+
323+
return ret;
324+
}
325+
326+
static ssize_t do_sign_write(struct file *file, const char __user *buf,
327+
size_t len, loff_t *ppos)
328+
{
329+
struct mox_rwtm *rwtm = file->private_data;
330+
struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply;
331+
struct armada_37xx_rwtm_tx_msg msg;
332+
loff_t dummy = 0;
333+
ssize_t ret;
334+
335+
/* the input is a SHA-512 hash, so exactly 64 bytes have to be read */
336+
if (len != 64)
337+
return -EINVAL;
338+
339+
/* if last result is not zero user has not read that information yet */
340+
if (rwtm->last_sig_done)
341+
return -EBUSY;
342+
343+
if (!mutex_trylock(&rwtm->busy))
344+
return -EBUSY;
345+
346+
/*
347+
* Here we have to send:
348+
* 1. Address of the input to sign.
349+
* The input is an array of 17 32-bit words, the first (most
350+
* significat) is 0, the rest 16 words are copied from the SHA-512
351+
* hash given by the user and converted from BE to LE.
352+
* 2. Address of the buffer where ECDSA signature value R shall be
353+
* stored by the rWTM firmware.
354+
* 3. Address of the buffer where ECDSA signature value S shall be
355+
* stored by the rWTM firmware.
356+
*/
357+
memset(rwtm->buf, 0, 4);
358+
ret = simple_write_to_buffer(rwtm->buf + 4, 64, &dummy, buf, len);
359+
if (ret < 0)
360+
goto unlock_mutex;
361+
be32_to_cpu_array(rwtm->buf, rwtm->buf, 17);
362+
363+
msg.command = MBOX_CMD_SIGN;
364+
msg.args[0] = 1;
365+
msg.args[1] = rwtm->buf_phys;
366+
msg.args[2] = rwtm->buf_phys + 68;
367+
msg.args[3] = rwtm->buf_phys + 2 * 68;
368+
ret = mbox_send_message(rwtm->mbox, &msg);
369+
if (ret < 0)
370+
goto unlock_mutex;
371+
372+
ret = wait_for_completion_interruptible(&rwtm->cmd_done);
373+
if (ret < 0)
374+
goto unlock_mutex;
375+
376+
ret = MBOX_STS_VALUE(reply->retval);
377+
if (MBOX_STS_ERROR(reply->retval) != MBOX_STS_SUCCESS)
378+
goto unlock_mutex;
379+
380+
/*
381+
* Here we read the R and S values of the ECDSA signature
382+
* computed by the rWTM firmware and convert their words from
383+
* LE to BE.
384+
*/
385+
memcpy(rwtm->last_sig, rwtm->buf + 68, 136);
386+
cpu_to_be32_array(rwtm->last_sig, rwtm->last_sig, 34);
387+
rwtm->last_sig_done = 1;
388+
389+
mutex_unlock(&rwtm->busy);
390+
return len;
391+
unlock_mutex:
392+
mutex_unlock(&rwtm->busy);
393+
return ret;
394+
}
395+
396+
static const struct file_operations do_sign_fops = {
397+
.owner = THIS_MODULE,
398+
.open = rwtm_debug_open,
399+
.read = do_sign_read,
400+
.write = do_sign_write,
401+
.llseek = no_llseek,
402+
};
403+
404+
static int rwtm_register_debugfs(struct mox_rwtm *rwtm)
405+
{
406+
struct dentry *root, *entry;
407+
408+
root = debugfs_create_dir("turris-mox-rwtm", NULL);
409+
410+
if (IS_ERR(root))
411+
return PTR_ERR(root);
412+
413+
entry = debugfs_create_file_unsafe("do_sign", 0600, root, rwtm,
414+
&do_sign_fops);
415+
if (IS_ERR(entry))
416+
goto err_remove;
417+
418+
rwtm->debugfs_root = root;
419+
420+
return 0;
421+
err_remove:
422+
debugfs_remove_recursive(root);
423+
return PTR_ERR(entry);
424+
}
425+
426+
static void rwtm_unregister_debugfs(struct mox_rwtm *rwtm)
427+
{
428+
debugfs_remove_recursive(rwtm->debugfs_root);
429+
}
430+
#else
431+
static inline int rwtm_register_debugfs(struct mox_rwtm *rwtm)
432+
{
433+
return 0;
434+
}
435+
436+
static inline void rwtm_unregister_debugfs(struct mox_rwtm *rwtm)
437+
{
438+
}
439+
#endif
440+
282441
static int turris_mox_rwtm_probe(struct platform_device *pdev)
283442
{
284443
struct mox_rwtm *rwtm;
@@ -340,6 +499,12 @@ static int turris_mox_rwtm_probe(struct platform_device *pdev)
340499
goto free_channel;
341500
}
342501

502+
ret = rwtm_register_debugfs(rwtm);
503+
if (ret < 0) {
504+
dev_err(dev, "Failed creating debugfs entries: %i\n", ret);
505+
goto free_channel;
506+
}
507+
343508
return 0;
344509

345510
free_channel:
@@ -355,6 +520,7 @@ static int turris_mox_rwtm_remove(struct platform_device *pdev)
355520
{
356521
struct mox_rwtm *rwtm = platform_get_drvdata(pdev);
357522

523+
rwtm_unregister_debugfs(rwtm);
358524
sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
359525
kobject_put(rwtm_to_kobj(rwtm));
360526
mbox_free_channel(rwtm->mbox);

0 commit comments

Comments
 (0)