You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next' into for-linus
Conflicts: security/integrity/evm/evm_crypto.c Resolved upstream fix vs. next conflict manually. Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
Digital Signature Verification API
|
||||
|
||||
CONTENTS
|
||||
|
||||
1. Introduction
|
||||
2. API
|
||||
3. User-space utilities
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
Digital signature verification API provides a method to verify digital signature.
|
||||
Currently digital signatures are used by the IMA/EVM integrity protection subsystem.
|
||||
|
||||
Digital signature verification is implemented using cut-down kernel port of
|
||||
GnuPG multi-precision integers (MPI) library. The kernel port provides
|
||||
memory allocation errors handling, has been refactored according to kernel
|
||||
coding style, and checkpatch.pl reported errors and warnings have been fixed.
|
||||
|
||||
Public key and signature consist of header and MPIs.
|
||||
|
||||
struct pubkey_hdr {
|
||||
uint8_t version; /* key format version */
|
||||
time_t timestamp; /* key made, always 0 for now */
|
||||
uint8_t algo;
|
||||
uint8_t nmpi;
|
||||
char mpi[0];
|
||||
} __packed;
|
||||
|
||||
struct signature_hdr {
|
||||
uint8_t version; /* signature format version */
|
||||
time_t timestamp; /* signature made */
|
||||
uint8_t algo;
|
||||
uint8_t hash;
|
||||
uint8_t keyid[8];
|
||||
uint8_t nmpi;
|
||||
char mpi[0];
|
||||
} __packed;
|
||||
|
||||
keyid equals to SHA1[12-19] over the total key content.
|
||||
Signature header is used as an input to generate a signature.
|
||||
Such approach insures that key or signature header could not be changed.
|
||||
It protects timestamp from been changed and can be used for rollback
|
||||
protection.
|
||||
|
||||
2. API
|
||||
|
||||
API currently includes only 1 function:
|
||||
|
||||
digsig_verify() - digital signature verification with public key
|
||||
|
||||
|
||||
/**
|
||||
* digsig_verify() - digital signature verification with public key
|
||||
* @keyring: keyring to search key in
|
||||
* @sig: digital signature
|
||||
* @sigen: length of the signature
|
||||
* @data: data
|
||||
* @datalen: length of the data
|
||||
* @return: 0 on success, -EINVAL otherwise
|
||||
*
|
||||
* Verifies data integrity against digital signature.
|
||||
* Currently only RSA is supported.
|
||||
* Normally hash of the content is used as a data for this function.
|
||||
*
|
||||
*/
|
||||
int digsig_verify(struct key *keyring, const char *sig, int siglen,
|
||||
const char *data, int datalen);
|
||||
|
||||
3. User-space utilities
|
||||
|
||||
The signing and key management utilities evm-utils provide functionality
|
||||
to generate signatures, to load keys into the kernel keyring.
|
||||
Keys can be in PEM or converted to the kernel format.
|
||||
When the key is added to the kernel keyring, the keyid defines the name
|
||||
of the key: 5D2B05FC633EE3E8 in the example bellow.
|
||||
|
||||
Here is example output of the keyctl utility.
|
||||
|
||||
$ keyctl show
|
||||
Session Keyring
|
||||
-3 --alswrv 0 0 keyring: _ses
|
||||
603976250 --alswrv 0 -1 \_ keyring: _uid.0
|
||||
817777377 --alswrv 0 0 \_ user: kmk
|
||||
891974900 --alswrv 0 0 \_ encrypted: evm-key
|
||||
170323636 --alswrv 0 0 \_ keyring: _module
|
||||
548221616 --alswrv 0 0 \_ keyring: _ima
|
||||
128198054 --alswrv 0 0 \_ keyring: _evm
|
||||
|
||||
$ keyctl list 128198054
|
||||
1 key in keyring:
|
||||
620789745: --alswrv 0 0 user: 5D2B05FC633EE3E8
|
||||
|
||||
|
||||
Dmitry Kasatkin
|
||||
06.10.2011
|
||||
@@ -1,5 +1,7 @@
|
||||
00-INDEX
|
||||
- this file.
|
||||
LSM.txt
|
||||
- description of the Linux Security Module framework.
|
||||
SELinux.txt
|
||||
- how to get started with the SELinux security enhancement.
|
||||
Smack.txt
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
Linux Security Module framework
|
||||
-------------------------------
|
||||
|
||||
The Linux Security Module (LSM) framework provides a mechanism for
|
||||
various security checks to be hooked by new kernel extensions. The name
|
||||
"module" is a bit of a misnomer since these extensions are not actually
|
||||
loadable kernel modules. Instead, they are selectable at build-time via
|
||||
CONFIG_DEFAULT_SECURITY and can be overridden at boot-time via the
|
||||
"security=..." kernel command line argument, in the case where multiple
|
||||
LSMs were built into a given kernel.
|
||||
|
||||
The primary users of the LSM interface are Mandatory Access Control
|
||||
(MAC) extensions which provide a comprehensive security policy. Examples
|
||||
include SELinux, Smack, Tomoyo, and AppArmor. In addition to the larger
|
||||
MAC extensions, other extensions can be built using the LSM to provide
|
||||
specific changes to system operation when these tweaks are not available
|
||||
in the core functionality of Linux itself.
|
||||
|
||||
Without a specific LSM built into the kernel, the default LSM will be the
|
||||
Linux capabilities system. Most LSMs choose to extend the capabilities
|
||||
system, building their checks on top of the defined capability hooks.
|
||||
For more details on capabilities, see capabilities(7) in the Linux
|
||||
man-pages project.
|
||||
|
||||
Based on http://kerneltrap.org/Linux/Documenting_Security_Module_Intent,
|
||||
a new LSM is accepted into the kernel when its intent (a description of
|
||||
what it tries to protect against and in what cases one would expect to
|
||||
use it) has been appropriately documented in Documentation/security/.
|
||||
This allows an LSM's code to be easily compared to its goals, and so
|
||||
that end users and distros can make a more informed decision about which
|
||||
LSMs suit their requirements.
|
||||
|
||||
For extensive documentation on the available LSM hook interfaces, please
|
||||
see include/linux/security.h.
|
||||
@@ -221,10 +221,10 @@ The Linux kernel supports the following types of credentials:
|
||||
(5) LSM
|
||||
|
||||
The Linux Security Module allows extra controls to be placed over the
|
||||
operations that a task may do. Currently Linux supports two main
|
||||
alternate LSM options: SELinux and Smack.
|
||||
operations that a task may do. Currently Linux supports several LSM
|
||||
options.
|
||||
|
||||
Both work by labelling the objects in a system and then applying sets of
|
||||
Some work by labelling the objects in a system and then applying sets of
|
||||
rules (policies) that say what operations a task with one label may do to
|
||||
an object with another label.
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ if TCG_TPM
|
||||
|
||||
config TCG_TIS
|
||||
tristate "TPM Interface Specification 1.2 Interface"
|
||||
depends on X86
|
||||
---help---
|
||||
If you have a TPM security chip that is compliant with the
|
||||
TCG TIS 1.2 TPM specification say Yes and it will be accessible
|
||||
@@ -35,6 +36,7 @@ config TCG_TIS
|
||||
|
||||
config TCG_NSC
|
||||
tristate "National Semiconductor TPM Interface"
|
||||
depends on X86
|
||||
---help---
|
||||
If you have a TPM security chip from National Semiconductor
|
||||
say Yes and it will be accessible from within Linux. To
|
||||
|
||||
+118
-21
@@ -27,6 +27,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include "tpm.h"
|
||||
|
||||
@@ -440,7 +441,6 @@ out:
|
||||
}
|
||||
|
||||
#define TPM_DIGEST_SIZE 20
|
||||
#define TPM_ERROR_SIZE 10
|
||||
#define TPM_RET_CODE_IDX 6
|
||||
|
||||
enum tpm_capabilities {
|
||||
@@ -469,12 +469,14 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
||||
len = tpm_transmit(chip,(u8 *) cmd, len);
|
||||
if (len < 0)
|
||||
return len;
|
||||
if (len == TPM_ERROR_SIZE) {
|
||||
err = be32_to_cpu(cmd->header.out.return_code);
|
||||
dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
else if (len < TPM_HEADER_SIZE)
|
||||
return -EFAULT;
|
||||
|
||||
err = be32_to_cpu(cmd->header.out.return_code);
|
||||
if (err != 0)
|
||||
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define TPM_INTERNAL_RESULT_SIZE 200
|
||||
@@ -530,7 +532,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
|
||||
|
||||
void tpm_get_timeouts(struct tpm_chip *chip)
|
||||
int tpm_get_timeouts(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_cmd_t tpm_cmd;
|
||||
struct timeout_t *timeout_cap;
|
||||
@@ -552,7 +554,7 @@ void tpm_get_timeouts(struct tpm_chip *chip)
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
|
||||
be32_to_cpu(tpm_cmd.header.out.length)
|
||||
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
|
||||
/* Don't overwrite default if value is 0 */
|
||||
@@ -583,12 +585,12 @@ duration:
|
||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||
"attempting to determine the durations");
|
||||
if (rc)
|
||||
return;
|
||||
return rc;
|
||||
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
|
||||
be32_to_cpu(tpm_cmd.header.out.length)
|
||||
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
|
||||
chip->vendor.duration[TPM_SHORT] =
|
||||
@@ -610,20 +612,36 @@ duration:
|
||||
chip->vendor.duration_adjusted = true;
|
||||
dev_info(chip->dev, "Adjusting TPM timeout parameters.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_get_timeouts);
|
||||
|
||||
void tpm_continue_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
u8 data[] = {
|
||||
0, 193, /* TPM_TAG_RQU_COMMAND */
|
||||
0, 0, 0, 10, /* length */
|
||||
0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */
|
||||
};
|
||||
#define TPM_ORD_CONTINUE_SELFTEST 83
|
||||
#define CONTINUE_SELFTEST_RESULT_SIZE 10
|
||||
|
||||
tpm_transmit(chip, data, sizeof(data));
|
||||
static struct tpm_input_header continue_selftest_header = {
|
||||
.tag = TPM_TAG_RQU_COMMAND,
|
||||
.length = cpu_to_be32(10),
|
||||
.ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
|
||||
};
|
||||
|
||||
/**
|
||||
* tpm_continue_selftest -- run TPM's selftest
|
||||
* @chip: TPM chip to use
|
||||
*
|
||||
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
|
||||
* a TPM error code.
|
||||
*/
|
||||
static int tpm_continue_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
struct tpm_cmd_t cmd;
|
||||
|
||||
cmd.header.in = continue_selftest_header;
|
||||
rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
|
||||
"continue selftest");
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_continue_selftest);
|
||||
|
||||
ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
|
||||
char *buf)
|
||||
@@ -718,7 +736,7 @@ static struct tpm_input_header pcrread_header = {
|
||||
.ordinal = TPM_ORDINAL_PCRREAD
|
||||
};
|
||||
|
||||
int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||
static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||
{
|
||||
int rc;
|
||||
struct tpm_cmd_t cmd;
|
||||
@@ -798,6 +816,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_pcr_extend);
|
||||
|
||||
/**
|
||||
* tpm_do_selftest - have the TPM continue its selftest and wait until it
|
||||
* can receive further commands
|
||||
* @chip: TPM chip to use
|
||||
*
|
||||
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
|
||||
* a TPM error code.
|
||||
*/
|
||||
int tpm_do_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
u8 digest[TPM_DIGEST_SIZE];
|
||||
unsigned int loops;
|
||||
unsigned int delay_msec = 1000;
|
||||
unsigned long duration;
|
||||
|
||||
duration = tpm_calc_ordinal_duration(chip,
|
||||
TPM_ORD_CONTINUE_SELFTEST);
|
||||
|
||||
loops = jiffies_to_msecs(duration) / delay_msec;
|
||||
|
||||
rc = tpm_continue_selftest(chip);
|
||||
/* This may fail if there was no TPM driver during a suspend/resume
|
||||
* cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
|
||||
*/
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
do {
|
||||
rc = __tpm_pcr_read(chip, 0, digest);
|
||||
if (rc != TPM_WARN_DOING_SELFTEST)
|
||||
return rc;
|
||||
msleep(delay_msec);
|
||||
} while (--loops > 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_do_selftest);
|
||||
|
||||
int tpm_send(u32 chip_num, void *cmd, size_t buflen)
|
||||
{
|
||||
struct tpm_chip *chip;
|
||||
@@ -1005,6 +1062,46 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_store_cancel);
|
||||
|
||||
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||
wait_queue_head_t *queue)
|
||||
{
|
||||
unsigned long stop;
|
||||
long rc;
|
||||
u8 status;
|
||||
|
||||
/* check current status */
|
||||
status = chip->vendor.status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
|
||||
stop = jiffies + timeout;
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
again:
|
||||
timeout = stop - jiffies;
|
||||
if ((long)timeout <= 0)
|
||||
return -ETIME;
|
||||
rc = wait_event_interruptible_timeout(*queue,
|
||||
((chip->vendor.status(chip)
|
||||
& mask) == mask),
|
||||
timeout);
|
||||
if (rc > 0)
|
||||
return 0;
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
msleep(TPM_TIMEOUT);
|
||||
status = chip->vendor.status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
} while (time_before(jiffies, stop));
|
||||
}
|
||||
return -ETIME;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
||||
/*
|
||||
* Device file system interface to the TPM
|
||||
*
|
||||
|
||||
@@ -38,6 +38,8 @@ enum tpm_addr {
|
||||
TPM_ADDR = 0x4E,
|
||||
};
|
||||
|
||||
#define TPM_WARN_DOING_SELFTEST 0x802
|
||||
#define TPM_HEADER_SIZE 10
|
||||
extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
|
||||
@@ -279,9 +281,9 @@ struct tpm_cmd_t {
|
||||
|
||||
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
|
||||
|
||||
extern void tpm_get_timeouts(struct tpm_chip *);
|
||||
extern int tpm_get_timeouts(struct tpm_chip *);
|
||||
extern void tpm_gen_interrupt(struct tpm_chip *);
|
||||
extern void tpm_continue_selftest(struct tpm_chip *);
|
||||
extern int tpm_do_selftest(struct tpm_chip *);
|
||||
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
|
||||
extern struct tpm_chip* tpm_register_hardware(struct device *,
|
||||
const struct tpm_vendor_specific *);
|
||||
@@ -294,7 +296,8 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
|
||||
extern void tpm_remove_hardware(struct device *);
|
||||
extern int tpm_pm_suspend(struct device *, pm_message_t);
|
||||
extern int tpm_pm_resume(struct device *);
|
||||
|
||||
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
|
||||
wait_queue_head_t *);
|
||||
#ifdef CONFIG_ACPI
|
||||
extern struct dentry ** tpm_bios_log_setup(char *);
|
||||
extern void tpm_bios_log_teardown(struct dentry **);
|
||||
|
||||
+27
-57
@@ -29,8 +29,6 @@
|
||||
#include <linux/freezer.h>
|
||||
#include "tpm.h"
|
||||
|
||||
#define TPM_HEADER_SIZE 10
|
||||
|
||||
enum tis_access {
|
||||
TPM_ACCESS_VALID = 0x80,
|
||||
TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
|
||||
@@ -193,54 +191,14 @@ static int get_burstcount(struct tpm_chip *chip)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||
wait_queue_head_t *queue)
|
||||
{
|
||||
unsigned long stop;
|
||||
long rc;
|
||||
u8 status;
|
||||
|
||||
/* check current status */
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
|
||||
stop = jiffies + timeout;
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
again:
|
||||
timeout = stop - jiffies;
|
||||
if ((long)timeout <= 0)
|
||||
return -ETIME;
|
||||
rc = wait_event_interruptible_timeout(*queue,
|
||||
((tpm_tis_status
|
||||
(chip) & mask) ==
|
||||
mask), timeout);
|
||||
if (rc > 0)
|
||||
return 0;
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
msleep(TPM_TIMEOUT);
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
} while (time_before(jiffies, stop));
|
||||
}
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
int size = 0, burstcnt;
|
||||
while (size < count &&
|
||||
wait_for_stat(chip,
|
||||
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
chip->vendor.timeout_c,
|
||||
&chip->vendor.read_queue)
|
||||
wait_for_tpm_stat(chip,
|
||||
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
chip->vendor.timeout_c,
|
||||
&chip->vendor.read_queue)
|
||||
== 0) {
|
||||
burstcnt = get_burstcount(chip);
|
||||
for (; burstcnt > 0 && size < count; burstcnt--)
|
||||
@@ -282,8 +240,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
status = tpm_tis_status(chip);
|
||||
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
|
||||
dev_err(chip->dev, "Error left over data\n");
|
||||
@@ -317,7 +275,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & TPM_STS_COMMAND_READY) == 0) {
|
||||
tpm_tis_ready(chip);
|
||||
if (wait_for_stat
|
||||
if (wait_for_tpm_stat
|
||||
(chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
|
||||
&chip->vendor.int_queue) < 0) {
|
||||
rc = -ETIME;
|
||||
@@ -333,8 +291,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
count++;
|
||||
}
|
||||
|
||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
status = tpm_tis_status(chip);
|
||||
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
|
||||
rc = -EIO;
|
||||
@@ -345,8 +303,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
/* write last byte */
|
||||
iowrite8(buf[count],
|
||||
chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
|
||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & TPM_STS_DATA_EXPECT) != 0) {
|
||||
rc = -EIO;
|
||||
@@ -381,7 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
|
||||
if (wait_for_stat
|
||||
if (wait_for_tpm_stat
|
||||
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
tpm_calc_ordinal_duration(chip, ordinal),
|
||||
&chip->vendor.read_queue) < 0) {
|
||||
@@ -432,6 +390,9 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||
out:
|
||||
itpm = rem_itpm;
|
||||
tpm_tis_ready(chip);
|
||||
/* some TPMs need a break here otherwise they will not work
|
||||
* correctly on the immediately subsequent command */
|
||||
msleep(chip->vendor.timeout_b);
|
||||
release_locality(chip, chip->vendor.locality, 0);
|
||||
|
||||
return rc;
|
||||
@@ -614,7 +575,17 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||
dev_dbg(dev, "\tData Avail Int Support\n");
|
||||
|
||||
/* get the timeouts before testing for irqs */
|
||||
tpm_get_timeouts(chip);
|
||||
if (tpm_get_timeouts(chip)) {
|
||||
dev_err(dev, "Could not get TPM timeouts and durations\n");
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (tpm_do_selftest(chip)) {
|
||||
dev_err(dev, "TPM self test failed\n");
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* INTERRUPT Setup */
|
||||
init_waitqueue_head(&chip->vendor.read_queue);
|
||||
@@ -722,7 +693,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||
list_add(&chip->vendor.list, &tis_chips);
|
||||
spin_unlock(&tis_lock);
|
||||
|
||||
tpm_continue_selftest(chip);
|
||||
|
||||
return 0;
|
||||
out_err:
|
||||
@@ -790,7 +760,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
|
||||
|
||||
ret = tpm_pm_resume(&dev->dev);
|
||||
if (!ret)
|
||||
tpm_continue_selftest(chip);
|
||||
tpm_do_selftest(chip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Copyright (C) 2011 Intel Corporation
|
||||
*
|
||||
* Author:
|
||||
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
|
||||
* <dmitry.kasatkin@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DIGSIG_H
|
||||
#define _DIGSIG_H
|
||||
|
||||
#include <linux/key.h>
|
||||
|
||||
enum pubkey_algo {
|
||||
PUBKEY_ALGO_RSA,
|
||||
PUBKEY_ALGO_MAX,
|
||||
};
|
||||
|
||||
enum digest_algo {
|
||||
DIGEST_ALGO_SHA1,
|
||||
DIGEST_ALGO_SHA256,
|
||||
DIGEST_ALGO_MAX
|
||||
};
|
||||
|
||||
struct pubkey_hdr {
|
||||
uint8_t version; /* key format version */
|
||||
time_t timestamp; /* key made, always 0 for now */
|
||||
uint8_t algo;
|
||||
uint8_t nmpi;
|
||||
char mpi[0];
|
||||
} __packed;
|
||||
|
||||
struct signature_hdr {
|
||||
uint8_t version; /* signature format version */
|
||||
time_t timestamp; /* signature made */
|
||||
uint8_t algo;
|
||||
uint8_t hash;
|
||||
uint8_t keyid[8];
|
||||
uint8_t nmpi;
|
||||
char mpi[0];
|
||||
} __packed;
|
||||
|
||||
#if defined(CONFIG_DIGSIG) || defined(CONFIG_DIGSIG_MODULE)
|
||||
|
||||
int digsig_verify(struct key *keyring, const char *sig, int siglen,
|
||||
const char *digest, int digestlen);
|
||||
|
||||
#else
|
||||
|
||||
static inline int digsig_verify(struct key *keyring, const char *sig,
|
||||
int siglen, const char *digest, int digestlen)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DIGSIG */
|
||||
|
||||
#endif /* _DIGSIG_H */
|
||||
@@ -92,6 +92,7 @@ struct key_type {
|
||||
|
||||
/* internal fields */
|
||||
struct list_head link; /* link in types list */
|
||||
struct lock_class_key lock_class; /* key->sem lock class */
|
||||
};
|
||||
|
||||
extern struct key_type key_type_keyring;
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/* mpi.h - Multi Precision Integers
|
||||
* Copyright (C) 1994, 1996, 1998, 1999,
|
||||
* 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNUPG.
|
||||
*
|
||||
* GNUPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GNUPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
* Note: This code is heavily based on the GNU MP Library.
|
||||
* Actually it's the same code with only minor changes in the
|
||||
* way the data is stored; this is to support the abstraction
|
||||
* of an optional secure memory allocation which may be used
|
||||
* to avoid revealing of sensitive data due to paging etc.
|
||||
* The GNU MP Library itself is published under the LGPL;
|
||||
* however I decided to publish this code under the plain GPL.
|
||||
*/
|
||||
|
||||
#ifndef G10_MPI_H
|
||||
#define G10_MPI_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* DSI defines */
|
||||
|
||||
#define SHA1_DIGEST_LENGTH 20
|
||||
|
||||
/*end of DSI defines */
|
||||
|
||||
#define BYTES_PER_MPI_LIMB (BITS_PER_LONG / 8)
|
||||
#define BITS_PER_MPI_LIMB BITS_PER_LONG
|
||||
|
||||
typedef unsigned long int mpi_limb_t;
|
||||
typedef signed long int mpi_limb_signed_t;
|
||||
|
||||
struct gcry_mpi {
|
||||
int alloced; /* array size (# of allocated limbs) */
|
||||
int nlimbs; /* number of valid limbs */
|
||||
int nbits; /* the real number of valid bits (info only) */
|
||||
int sign; /* indicates a negative number */
|
||||
unsigned flags; /* bit 0: array must be allocated in secure memory space */
|
||||
/* bit 1: not used */
|
||||
/* bit 2: the limb is a pointer to some m_alloced data */
|
||||
mpi_limb_t *d; /* array with the limbs */
|
||||
};
|
||||
|
||||
typedef struct gcry_mpi *MPI;
|
||||
|
||||
#define MPI_NULL NULL
|
||||
|
||||
#define mpi_get_nlimbs(a) ((a)->nlimbs)
|
||||
#define mpi_is_neg(a) ((a)->sign)
|
||||
|
||||
/*-- mpiutil.c --*/
|
||||
MPI mpi_alloc(unsigned nlimbs);
|
||||
MPI mpi_alloc_secure(unsigned nlimbs);
|
||||
MPI mpi_alloc_like(MPI a);
|
||||
void mpi_free(MPI a);
|
||||
int mpi_resize(MPI a, unsigned nlimbs);
|
||||
int mpi_copy(MPI *copy, const MPI a);
|
||||
void mpi_clear(MPI a);
|
||||
int mpi_set(MPI w, MPI u);
|
||||
int mpi_set_ui(MPI w, ulong u);
|
||||
MPI mpi_alloc_set_ui(unsigned long u);
|
||||
void mpi_m_check(MPI a);
|
||||
void mpi_swap(MPI a, MPI b);
|
||||
|
||||
/*-- mpicoder.c --*/
|
||||
MPI do_encode_md(const void *sha_buffer, unsigned nbits);
|
||||
MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
|
||||
int mpi_fromstr(MPI val, const char *str);
|
||||
u32 mpi_get_keyid(MPI a, u32 *keyid);
|
||||
void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign);
|
||||
void *mpi_get_secure_buffer(MPI a, unsigned *nbytes, int *sign);
|
||||
int mpi_set_buffer(MPI a, const void *buffer, unsigned nbytes, int sign);
|
||||
|
||||
#define log_mpidump g10_log_mpidump
|
||||
|
||||
/*-- mpi-add.c --*/
|
||||
int mpi_add_ui(MPI w, MPI u, ulong v);
|
||||
int mpi_add(MPI w, MPI u, MPI v);
|
||||
int mpi_addm(MPI w, MPI u, MPI v, MPI m);
|
||||
int mpi_sub_ui(MPI w, MPI u, ulong v);
|
||||
int mpi_sub(MPI w, MPI u, MPI v);
|
||||
int mpi_subm(MPI w, MPI u, MPI v, MPI m);
|
||||
|
||||
/*-- mpi-mul.c --*/
|
||||
int mpi_mul_ui(MPI w, MPI u, ulong v);
|
||||
int mpi_mul_2exp(MPI w, MPI u, ulong cnt);
|
||||
int mpi_mul(MPI w, MPI u, MPI v);
|
||||
int mpi_mulm(MPI w, MPI u, MPI v, MPI m);
|
||||
|
||||
/*-- mpi-div.c --*/
|
||||
ulong mpi_fdiv_r_ui(MPI rem, MPI dividend, ulong divisor);
|
||||
int mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor);
|
||||
int mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor);
|
||||
int mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor);
|
||||
int mpi_tdiv_r(MPI rem, MPI num, MPI den);
|
||||
int mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den);
|
||||
int mpi_tdiv_q_2exp(MPI w, MPI u, unsigned count);
|
||||
int mpi_divisible_ui(const MPI dividend, ulong divisor);
|
||||
|
||||
/*-- mpi-gcd.c --*/
|
||||
int mpi_gcd(MPI g, const MPI a, const MPI b);
|
||||
|
||||
/*-- mpi-pow.c --*/
|
||||
int mpi_pow(MPI w, MPI u, MPI v);
|
||||
int mpi_powm(MPI res, MPI base, MPI exp, MPI mod);
|
||||
|
||||
/*-- mpi-mpow.c --*/
|
||||
int mpi_mulpowm(MPI res, MPI *basearray, MPI *exparray, MPI mod);
|
||||
|
||||
/*-- mpi-cmp.c --*/
|
||||
int mpi_cmp_ui(MPI u, ulong v);
|
||||
int mpi_cmp(MPI u, MPI v);
|
||||
|
||||
/*-- mpi-scan.c --*/
|
||||
int mpi_getbyte(MPI a, unsigned idx);
|
||||
void mpi_putbyte(MPI a, unsigned idx, int value);
|
||||
unsigned mpi_trailing_zeros(MPI a);
|
||||
|
||||
/*-- mpi-bit.c --*/
|
||||
void mpi_normalize(MPI a);
|
||||
unsigned mpi_get_nbits(MPI a);
|
||||
int mpi_test_bit(MPI a, unsigned n);
|
||||
int mpi_set_bit(MPI a, unsigned n);
|
||||
int mpi_set_highbit(MPI a, unsigned n);
|
||||
void mpi_clear_highbit(MPI a, unsigned n);
|
||||
void mpi_clear_bit(MPI a, unsigned n);
|
||||
int mpi_rshift(MPI x, MPI a, unsigned n);
|
||||
|
||||
/*-- mpi-inv.c --*/
|
||||
int mpi_invm(MPI x, MPI u, MPI v);
|
||||
|
||||
#endif /*G10_MPI_H */
|
||||
@@ -590,6 +590,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @reqprot contains the protection requested by the application.
|
||||
* @prot contains the protection that will be applied by the kernel.
|
||||
* @flags contains the operational flags.
|
||||
* @addr contains virtual address that will be used for the operation.
|
||||
* @addr_only contains a boolean: 0 if file-backed VMA, otherwise 1.
|
||||
* Return 0 if permission is granted.
|
||||
* @file_mprotect:
|
||||
* Check permissions before changing memory access permissions.
|
||||
@@ -2044,7 +2046,7 @@ static inline void security_inode_free(struct inode *inode)
|
||||
static inline int security_inode_init_security(struct inode *inode,
|
||||
struct inode *dir,
|
||||
const struct qstr *qstr,
|
||||
initxattrs initxattrs,
|
||||
const initxattrs initxattrs,
|
||||
void *fs_data)
|
||||
{
|
||||
return 0;
|
||||
|
||||
+25
@@ -276,4 +276,29 @@ config CORDIC
|
||||
so its calculations are in fixed point. Modules can select this
|
||||
when they require this function. Module will be called cordic.
|
||||
|
||||
config MPILIB
|
||||
tristate "Multiprecision maths library"
|
||||
help
|
||||
Multiprecision maths library from GnuPG.
|
||||
It is used to implement RSA digital signature verification,
|
||||
which is used by IMA/EVM digital signature extension.
|
||||
|
||||
config MPILIB_EXTRA
|
||||
bool "Multiprecision maths library - additional sources"
|
||||
depends on MPILIB
|
||||
help
|
||||
Multiprecision maths library from GnuPG.
|
||||
It is used to implement RSA digital signature verification,
|
||||
which is used by IMA/EVM digital signature extension.
|
||||
This code in unnecessary for RSA digital signature verification,
|
||||
and can be compiled if needed.
|
||||
|
||||
config DIGSIG
|
||||
tristate "In-kernel signature checker"
|
||||
depends on KEYS
|
||||
select MPILIB
|
||||
help
|
||||
Digital signature verification. Currently only RSA is supported.
|
||||
Implementation is done using GnuPG MPI library
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -115,6 +115,9 @@ obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o
|
||||
|
||||
obj-$(CONFIG_CORDIC) += cordic.o
|
||||
|
||||
obj-$(CONFIG_MPILIB) += mpi/
|
||||
obj-$(CONFIG_DIGSIG) += digsig.o
|
||||
|
||||
hostprogs-y := gen_crc32table
|
||||
clean-files := crc32table.h
|
||||
|
||||
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Nokia Corporation
|
||||
* Copyright (C) 2011 Intel Corporation
|
||||
*
|
||||
* Author:
|
||||
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
|
||||
* <dmitry.kasatkin@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* File: sign.c
|
||||
* implements signature (RSA) verification
|
||||
* pkcs decoding is based on LibTomCrypt code
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/key.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <keys/user-type.h>
|
||||
#include <linux/mpi.h>
|
||||
#include <linux/digsig.h>
|
||||
|
||||
static struct crypto_shash *shash;
|
||||
|
||||
static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg,
|
||||
unsigned long msglen,
|
||||
unsigned long modulus_bitlen,
|
||||
unsigned char *out,
|
||||
unsigned long *outlen,
|
||||
int *is_valid)
|
||||
{
|
||||
unsigned long modulus_len, ps_len, i;
|
||||
int result;
|
||||
|
||||
/* default to invalid packet */
|
||||
*is_valid = 0;
|
||||
|
||||
modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
|
||||
|
||||
/* test message size */
|
||||
if ((msglen > modulus_len) || (modulus_len < 11))
|
||||
return -EINVAL;
|
||||
|
||||
/* separate encoded message */
|
||||
if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1)) {
|
||||
result = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
for (i = 2; i < modulus_len - 1; i++)
|
||||
if (msg[i] != 0xFF)
|
||||
break;
|
||||
|
||||
/* separator check */
|
||||
if (msg[i] != 0) {
|
||||
/* There was no octet with hexadecimal value 0x00
|
||||
to separate ps from m. */
|
||||
result = -EINVAL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ps_len = i - 2;
|
||||
|
||||
if (*outlen < (msglen - (2 + ps_len + 1))) {
|
||||
*outlen = msglen - (2 + ps_len + 1);
|
||||
result = -EOVERFLOW;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
*outlen = (msglen - (2 + ps_len + 1));
|
||||
memcpy(out, &msg[2 + ps_len + 1], *outlen);
|
||||
|
||||
/* valid packet */
|
||||
*is_valid = 1;
|
||||
result = 0;
|
||||
bail:
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* RSA Signature verification with public key
|
||||
*/
|
||||
static int digsig_verify_rsa(struct key *key,
|
||||
const char *sig, int siglen,
|
||||
const char *h, int hlen)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
unsigned long len;
|
||||
unsigned long mlen, mblen;
|
||||
unsigned nret, l;
|
||||
int valid, head, i;
|
||||
unsigned char *out1 = NULL, *out2 = NULL;
|
||||
MPI in = NULL, res = NULL, pkey[2];
|
||||
uint8_t *p, *datap, *endp;
|
||||
struct user_key_payload *ukp;
|
||||
struct pubkey_hdr *pkh;
|
||||
|
||||
down_read(&key->sem);
|
||||
ukp = key->payload.data;
|
||||
pkh = (struct pubkey_hdr *)ukp->data;
|
||||
|
||||
if (pkh->version != 1)
|
||||
goto err1;
|
||||
|
||||
if (pkh->algo != PUBKEY_ALGO_RSA)
|
||||
goto err1;
|
||||
|
||||
if (pkh->nmpi != 2)
|
||||
goto err1;
|
||||
|
||||
datap = pkh->mpi;
|
||||
endp = datap + ukp->datalen;
|
||||
|
||||
for (i = 0; i < pkh->nmpi; i++) {
|
||||
unsigned int remaining = endp - datap;
|
||||
pkey[i] = mpi_read_from_buffer(datap, &remaining);
|
||||
datap += remaining;
|
||||
}
|
||||
|
||||
mblen = mpi_get_nbits(pkey[0]);
|
||||
mlen = (mblen + 7)/8;
|
||||
|
||||
err = -ENOMEM;
|
||||
|
||||
out1 = kzalloc(mlen, GFP_KERNEL);
|
||||
if (!out1)
|
||||
goto err;
|
||||
|
||||
out2 = kzalloc(mlen, GFP_KERNEL);
|
||||
if (!out2)
|
||||
goto err;
|
||||
|
||||
nret = siglen;
|
||||
in = mpi_read_from_buffer(sig, &nret);
|
||||
if (!in)
|
||||
goto err;
|
||||
|
||||
res = mpi_alloc(mpi_get_nlimbs(in) * 2);
|
||||
if (!res)
|
||||
goto err;
|
||||
|
||||
err = mpi_powm(res, in, pkey[1], pkey[0]);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
p = mpi_get_buffer(res, &l, NULL);
|
||||
if (!p) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
len = mlen;
|
||||
head = len - l;
|
||||
memset(out1, 0, head);
|
||||
memcpy(out1 + head, p, l);
|
||||
|
||||
err = -EINVAL;
|
||||
pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len, &valid);
|
||||
|
||||
if (valid && len == hlen)
|
||||
err = memcmp(out2, h, hlen);
|
||||
|
||||
err:
|
||||
mpi_free(in);
|
||||
mpi_free(res);
|
||||
kfree(out1);
|
||||
kfree(out2);
|
||||
mpi_free(pkey[0]);
|
||||
mpi_free(pkey[1]);
|
||||
err1:
|
||||
up_read(&key->sem);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* digsig_verify() - digital signature verification with public key
|
||||
* @keyring: keyring to search key in
|
||||
* @sig: digital signature
|
||||
* @sigen: length of the signature
|
||||
* @data: data
|
||||
* @datalen: length of the data
|
||||
* @return: 0 on success, -EINVAL otherwise
|
||||
*
|
||||
* Verifies data integrity against digital signature.
|
||||
* Currently only RSA is supported.
|
||||
* Normally hash of the content is used as a data for this function.
|
||||
*
|
||||
*/
|
||||
int digsig_verify(struct key *keyring, const char *sig, int siglen,
|
||||
const char *data, int datalen)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
struct signature_hdr *sh = (struct signature_hdr *)sig;
|
||||
struct shash_desc *desc = NULL;
|
||||
unsigned char hash[SHA1_DIGEST_SIZE];
|
||||
struct key *key;
|
||||
char name[20];
|
||||
|
||||
if (siglen < sizeof(*sh) + 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (sh->algo != PUBKEY_ALGO_RSA)
|
||||
return -ENOTSUPP;
|
||||
|
||||
sprintf(name, "%llX", __be64_to_cpup((uint64_t *)sh->keyid));
|
||||
|
||||
if (keyring) {
|
||||
/* search in specific keyring */
|
||||
key_ref_t kref;
|
||||
kref = keyring_search(make_key_ref(keyring, 1UL),
|
||||
&key_type_user, name);
|
||||
if (IS_ERR(kref))
|
||||
key = ERR_PTR(PTR_ERR(kref));
|
||||
else
|
||||
key = key_ref_to_ptr(kref);
|
||||
} else {
|
||||
key = request_key(&key_type_user, name, NULL);
|
||||
}
|
||||
if (IS_ERR(key)) {
|
||||
pr_err("key not found, id: %s\n", name);
|
||||
return PTR_ERR(key);
|
||||
}
|
||||
|
||||
desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(shash),
|
||||
GFP_KERNEL);
|
||||
if (!desc)
|
||||
goto err;
|
||||
|
||||
desc->tfm = shash;
|
||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||
|
||||
crypto_shash_init(desc);
|
||||
crypto_shash_update(desc, data, datalen);
|
||||
crypto_shash_update(desc, sig, sizeof(*sh));
|
||||
crypto_shash_final(desc, hash);
|
||||
|
||||
kfree(desc);
|
||||
|
||||
/* pass signature mpis address */
|
||||
err = digsig_verify_rsa(key, sig + sizeof(*sh), siglen - sizeof(*sh),
|
||||
hash, sizeof(hash));
|
||||
|
||||
err:
|
||||
key_put(key);
|
||||
|
||||
return err ? -EINVAL : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(digsig_verify);
|
||||
|
||||
static int __init digsig_init(void)
|
||||
{
|
||||
shash = crypto_alloc_shash("sha1", 0, 0);
|
||||
if (IS_ERR(shash)) {
|
||||
pr_err("shash allocation failed\n");
|
||||
return PTR_ERR(shash);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void __exit digsig_cleanup(void)
|
||||
{
|
||||
crypto_free_shash(shash);
|
||||
}
|
||||
|
||||
module_init(digsig_init);
|
||||
module_exit(digsig_cleanup);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# MPI multiprecision maths library (from gpg)
|
||||
#
|
||||
|
||||
obj-$(CONFIG_MPILIB) = mpi.o
|
||||
|
||||
mpi-y = \
|
||||
generic_mpih-lshift.o \
|
||||
generic_mpih-mul1.o \
|
||||
generic_mpih-mul2.o \
|
||||
generic_mpih-mul3.o \
|
||||
generic_mpih-rshift.o \
|
||||
generic_mpih-sub1.o \
|
||||
generic_mpih-add1.o \
|
||||
mpicoder.o \
|
||||
mpi-bit.o \
|
||||
mpih-cmp.o \
|
||||
mpih-div.o \
|
||||
mpih-mul.o \
|
||||
mpi-pow.o \
|
||||
mpiutil.o
|
||||
|
||||
mpi-$(CONFIG_MPILIB_EXTRA) += \
|
||||
mpi-add.o \
|
||||
mpi-div.o \
|
||||
mpi-cmp.o \
|
||||
mpi-gcd.o \
|
||||
mpi-inline.o \
|
||||
mpi-inv.o \
|
||||
mpi-mpow.o \
|
||||
mpi-mul.o \
|
||||
mpi-scan.o
|
||||
@@ -0,0 +1,4 @@
|
||||
/* This file defines some basic constants for the MPI machinery. We
|
||||
* need to define the types on a per-CPU basis, so it is done with
|
||||
* this file here. */
|
||||
#define BYTES_PER_MPI_LIMB (SIZEOF_UNSIGNED_LONG)
|
||||
@@ -0,0 +1,61 @@
|
||||
/* mpihelp-add_1.c - MPI helper functions
|
||||
* Copyright (C) 1994, 1996, 1997, 1998,
|
||||
* 2000 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
* Note: This code is heavily based on the GNU MP Library.
|
||||
* Actually it's the same code with only minor changes in the
|
||||
* way the data is stored; this is to support the abstraction
|
||||
* of an optional secure memory allocation which may be used
|
||||
* to avoid revealing of sensitive data due to paging etc.
|
||||
* The GNU MP Library itself is published under the LGPL;
|
||||
* however I decided to publish this code under the plain GPL.
|
||||
*/
|
||||
|
||||
#include "mpi-internal.h"
|
||||
#include "longlong.h"
|
||||
|
||||
mpi_limb_t
|
||||
mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr,
|
||||
mpi_ptr_t s2_ptr, mpi_size_t size)
|
||||
{
|
||||
mpi_limb_t x, y, cy;
|
||||
mpi_size_t j;
|
||||
|
||||
/* The loop counter and index J goes from -SIZE to -1. This way
|
||||
the loop becomes faster. */
|
||||
j = -size;
|
||||
|
||||
/* Offset the base pointers to compensate for the negative indices. */
|
||||
s1_ptr -= j;
|
||||
s2_ptr -= j;
|
||||
res_ptr -= j;
|
||||
|
||||
cy = 0;
|
||||
do {
|
||||
y = s2_ptr[j];
|
||||
x = s1_ptr[j];
|
||||
y += cy; /* add previous carry to one addend */
|
||||
cy = y < cy; /* get out carry from that addition */
|
||||
y += x; /* add other addend */
|
||||
cy += y < x; /* get out carry from that add, combine */
|
||||
res_ptr[j] = y;
|
||||
} while (++j);
|
||||
|
||||
return cy;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* mpihelp-lshift.c - MPI helper functions
|
||||
* Copyright (C) 1994, 1996, 1998, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
* Note: This code is heavily based on the GNU MP Library.
|
||||
* Actually it's the same code with only minor changes in the
|
||||
* way the data is stored; this is to support the abstraction
|
||||
* of an optional secure memory allocation which may be used
|
||||
* to avoid revealing of sensitive data due to paging etc.
|
||||
* The GNU MP Library itself is published under the LGPL;
|
||||
* however I decided to publish this code under the plain GPL.
|
||||
*/
|
||||
|
||||
#include "mpi-internal.h"
|
||||
|
||||
/* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left
|
||||
* and store the USIZE least significant digits of the result at WP.
|
||||
* Return the bits shifted out from the most significant digit.
|
||||
*
|
||||
* Argument constraints:
|
||||
* 1. 0 < CNT < BITS_PER_MP_LIMB
|
||||
* 2. If the result is to be written over the input, WP must be >= UP.
|
||||
*/
|
||||
|
||||
mpi_limb_t
|
||||
mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned int cnt)
|
||||
{
|
||||
mpi_limb_t high_limb, low_limb;
|
||||
unsigned sh_1, sh_2;
|
||||
mpi_size_t i;
|
||||
mpi_limb_t retval;
|
||||
|
||||
sh_1 = cnt;
|
||||
wp += 1;
|
||||
sh_2 = BITS_PER_MPI_LIMB - sh_1;
|
||||
i = usize - 1;
|
||||
low_limb = up[i];
|
||||
retval = low_limb >> sh_2;
|
||||
high_limb = low_limb;
|
||||
while (--i >= 0) {
|
||||
low_limb = up[i];
|
||||
wp[i] = (high_limb << sh_1) | (low_limb >> sh_2);
|
||||
high_limb = low_limb;
|
||||
}
|
||||
wp[i] = high_limb << sh_1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/* mpihelp-mul_1.c - MPI helper functions
|
||||
* Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*
|
||||
* Note: This code is heavily based on the GNU MP Library.
|
||||
* Actually it's the same code with only minor changes in the
|
||||
* way the data is stored; this is to support the abstraction
|
||||
* of an optional secure memory allocation which may be used
|
||||
* to avoid revealing of sensitive data due to paging etc.
|
||||
* The GNU MP Library itself is published under the LGPL;
|
||||
* however I decided to publish this code under the plain GPL.
|
||||
*/
|
||||
|
||||
#include "mpi-internal.h"
|
||||
#include "longlong.h"
|
||||
|
||||
mpi_limb_t
|
||||
mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size,
|
||||
mpi_limb_t s2_limb)
|
||||
{
|
||||
mpi_limb_t cy_limb;
|
||||
mpi_size_t j;
|
||||
mpi_limb_t prod_high, prod_low;
|
||||
|
||||
/* The loop counter and index J goes from -S1_SIZE to -1. This way
|
||||
* the loop becomes faster. */
|
||||
j = -s1_size;
|
||||
|
||||
/* Offset the base pointers to compensate for the negative indices. */
|
||||
s1_ptr -= j;
|
||||
res_ptr -= j;
|
||||
|
||||
cy_limb = 0;
|
||||
do {
|
||||
umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb);
|
||||
prod_low += cy_limb;
|
||||
cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high;
|
||||
res_ptr[j] = prod_low;
|
||||
} while (++j);
|
||||
|
||||
return cy_limb;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user