summaryrefslogtreecommitdiffstats
path: root/freed-ora/current/master
diff options
context:
space:
mode:
authorAlexandre Oliva <lxoliva@fsfla.org>2013-02-22 12:27:55 +0000
committerAlexandre Oliva <lxoliva@fsfla.org>2013-02-22 12:27:55 +0000
commit9169213b73b782ca297b41690853e444e7f3d0bc (patch)
treed620248cc4e36de7cb746fd381ca65cfa8a74429 /freed-ora/current/master
parent3f6b54fa86b174959bdf4e201055c673265162ef (diff)
downloadlinux-libre-raptor-9169213b73b782ca297b41690853e444e7f3d0bc.tar.gz
linux-libre-raptor-9169213b73b782ca297b41690853e444e7f3d0bc.zip
3.8.0-2.fc19.gnu
Diffstat (limited to 'freed-ora/current/master')
-rw-r--r--freed-ora/current/master/0001-bluetooth-Add-support-for-atheros-04ca-3004-device-t.patch61
-rw-r--r--freed-ora/current/master/alps-v2.patch2494
-rw-r--r--freed-ora/current/master/config-generic7
-rw-r--r--freed-ora/current/master/config-x86-generic5
-rw-r--r--freed-ora/current/master/devel-pekey-secure-boot-20130219.patch5861
-rw-r--r--freed-ora/current/master/kernel.spec24
6 files changed, 8446 insertions, 6 deletions
diff --git a/freed-ora/current/master/0001-bluetooth-Add-support-for-atheros-04ca-3004-device-t.patch b/freed-ora/current/master/0001-bluetooth-Add-support-for-atheros-04ca-3004-device-t.patch
new file mode 100644
index 000000000..a14532b22
--- /dev/null
+++ b/freed-ora/current/master/0001-bluetooth-Add-support-for-atheros-04ca-3004-device-t.patch
@@ -0,0 +1,61 @@
+From fe7963cbe464048cfae4523975aa208a6c7dc420 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Mon, 18 Feb 2013 10:32:13 -0500
+Subject: [PATCH] bluetooth: Add support for atheros 04ca:3004 device to ath3k
+
+Yet another version of the atheros bluetooth chipset
+
+T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=01 Dev#= 3 Spd=12 MxCh= 0
+D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
+P: Vendor=04ca ProdID=3004 Rev=00.01
+S: Manufacturer=Atheros Communications
+S: Product=Bluetooth USB Host Controller
+S: SerialNumber=Alaska Day 2006
+C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA
+I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb
+
+This resolves https://bugzilla.redhat.com/show_bug.cgi?id=844750
+
+Reported-by: niktr@mail.ru
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ drivers/bluetooth/ath3k.c | 2 ++
+ drivers/bluetooth/btusb.c | 1 +
+ 2 files changed, 3 insertions(+)
+
+diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
+index 33c9a44..b9908dd 100644
+--- a/drivers/bluetooth/ath3k.c
++++ b/drivers/bluetooth/ath3k.c
+@@ -76,6 +76,7 @@ static struct usb_device_id ath3k_table[] = {
+ { USB_DEVICE(0x0CF3, 0x3004) },
+ { USB_DEVICE(0x0CF3, 0x311D) },
+ { USB_DEVICE(0x13d3, 0x3375) },
++ { USB_DEVICE(0x04CA, 0x3004) },
+ { USB_DEVICE(0x04CA, 0x3005) },
+ { USB_DEVICE(0x04CA, 0x3006) },
+ { USB_DEVICE(0x04CA, 0x3008) },
+@@ -108,6 +109,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
+ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
++ { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index 7e351e3..59cde8e 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -134,6 +134,7 @@ static struct usb_device_id blacklist_table[] = {
+ { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
++ { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
+--
+1.8.1.2
+
diff --git a/freed-ora/current/master/alps-v2.patch b/freed-ora/current/master/alps-v2.patch
new file mode 100644
index 000000000..d394c4a92
--- /dev/null
+++ b/freed-ora/current/master/alps-v2.patch
@@ -0,0 +1,2494 @@
+From f822982515378982dc8d8e6058579288d0ee3cff Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 20:55:19 -0800
+Subject: [PATCH 01/15] Input: ALPS - document the alps.h data structures
+
+Add kernel-doc markup.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.h | 74 ++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 61 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index ae1ac35..67be4e5 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -17,30 +17,78 @@
+ #define ALPS_PROTO_V3 2
+ #define ALPS_PROTO_V4 3
+
++/**
++ * struct alps_model_info - touchpad ID table
++ * @signature: E7 response string to match.
++ * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response
++ * (aka command mode response) identifies the firmware minor version. This
++ * can be used to distinguish different hardware models which are not
++ * uniquely identifiable through their E7 responses.
++ * @proto_version: Indicates V1/V2/V3/...
++ * @byte0: Helps figure out whether a position report packet matches the
++ * known format for this model. The first byte of the report, ANDed with
++ * mask0, should match byte0.
++ * @mask0: The mask used to check the first byte of the report.
++ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
++ *
++ * Many (but not all) ALPS touchpads can be identified by looking at the
++ * values returned in the "E7 report" and/or the "EC report." This table
++ * lists a number of such touchpads.
++ */
+ struct alps_model_info {
+- unsigned char signature[3];
+- unsigned char command_mode_resp; /* v3/v4 only */
++ unsigned char signature[3];
++ unsigned char command_mode_resp;
+ unsigned char proto_version;
+- unsigned char byte0, mask0;
+- unsigned char flags;
++ unsigned char byte0, mask0;
++ unsigned char flags;
+ };
+
++/**
++ * struct alps_nibble_commands - encodings for register accesses
++ * @command: PS/2 command used for the nibble
++ * @data: Data supplied as an argument to the PS/2 command, if applicable
++ *
++ * The ALPS protocol uses magic sequences to transmit binary data to the
++ * touchpad, as it is generally not OK to send arbitrary bytes out the
++ * PS/2 port. Each of the sequences in this table sends one nibble of the
++ * register address or (write) data. Different versions of the ALPS protocol
++ * use slightly different encodings.
++ */
+ struct alps_nibble_commands {
+ int command;
+ unsigned char data;
+ };
+
++/**
++ * struct alps_data - private data structure for the ALPS driver
++ * @dev2: "Relative" device used to report trackstick or mouse activity.
++ * @phys: Physical path for the relative device.
++ * @i: Information on the detected touchpad model.
++ * @nibble_commands: Command mapping used for touchpad register accesses.
++ * @addr_command: Command used to tell the touchpad that a register address
++ * follows.
++ * @prev_fin: Finger bit from previous packet.
++ * @multi_packet: Multi-packet data in progress.
++ * @multi_data: Saved multi-packet data.
++ * @x1: First X coordinate from last MT report.
++ * @x2: Second X coordinate from last MT report.
++ * @y1: First Y coordinate from last MT report.
++ * @y2: Second Y coordinate from last MT report.
++ * @fingers: Number of fingers from last MT report.
++ * @quirks: Bitmap of ALPS_QUIRK_*.
++ * @timer: Timer for flushing out the final report packet in the stream.
++ */
+ struct alps_data {
+- struct input_dev *dev2; /* Relative device */
+- char phys[32]; /* Phys */
+- const struct alps_model_info *i;/* Info */
++ struct input_dev *dev2;
++ char phys[32];
++ const struct alps_model_info *i;
+ const struct alps_nibble_commands *nibble_commands;
+- int addr_command; /* Command to set register address */
+- int prev_fin; /* Finger bit from previous packet */
+- int multi_packet; /* Multi-packet data in progress */
+- unsigned char multi_data[6]; /* Saved multi-packet data */
+- int x1, x2, y1, y2; /* Coordinates from last MT report */
+- int fingers; /* Number of fingers from MT report */
++ int addr_command;
++ int prev_fin;
++ int multi_packet;
++ unsigned char multi_data[6];
++ int x1, x2, y1, y2;
++ int fingers;
+ u8 quirks;
+ struct timer_list timer;
+ };
+--
+1.8.1.2
+
+
+From 196069863604cb55061a02ad5f046c5e4054ba54 Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 20:56:33 -0800
+Subject: [PATCH 02/15] Input: ALPS - copy "model" info into alps_data struct
+
+Not every type of ALPS touchpad is well-suited to table-based detection.
+Start moving the various alps_model_data attributes into the alps_data
+struct so that we don't need a unique table entry for every possible
+permutation of protocol version, flags, byte0/mask0, etc.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 63 +++++++++++++++++++++++-----------------------
+ drivers/input/mouse/alps.h | 14 +++++++++--
+ 2 files changed, 43 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index e229fa3..33ee6e0 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -122,10 +122,10 @@ static const struct alps_model_info alps_model_data[] = {
+
+ /* Packet formats are described in Documentation/input/alps.txt */
+
+-static bool alps_is_valid_first_byte(const struct alps_model_info *model,
++static bool alps_is_valid_first_byte(struct alps_data *priv,
+ unsigned char data)
+ {
+- return (data & model->mask0) == model->byte0;
++ return (data & priv->mask0) == priv->byte0;
+ }
+
+ static void alps_report_buttons(struct psmouse *psmouse,
+@@ -158,14 +158,13 @@ static void alps_report_buttons(struct psmouse *psmouse,
+ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+- const struct alps_model_info *model = priv->i;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ struct input_dev *dev2 = priv->dev2;
+ int x, y, z, ges, fin, left, right, middle;
+ int back = 0, forward = 0;
+
+- if (model->proto_version == ALPS_PROTO_V1) {
++ if (priv->proto_version == ALPS_PROTO_V1) {
+ left = packet[2] & 0x10;
+ right = packet[2] & 0x08;
+ middle = 0;
+@@ -181,12 +180,12 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
+ z = packet[5];
+ }
+
+- if (model->flags & ALPS_FW_BK_1) {
++ if (priv->flags & ALPS_FW_BK_1) {
+ back = packet[0] & 0x10;
+ forward = packet[2] & 4;
+ }
+
+- if (model->flags & ALPS_FW_BK_2) {
++ if (priv->flags & ALPS_FW_BK_2) {
+ back = packet[3] & 4;
+ forward = packet[2] & 4;
+ if ((middle = forward && back))
+@@ -196,7 +195,7 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
+ ges = packet[2] & 1;
+ fin = packet[2] & 2;
+
+- if ((model->flags & ALPS_DUALPOINT) && z == 127) {
++ if ((priv->flags & ALPS_DUALPOINT) && z == 127) {
+ input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
+ input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
+
+@@ -239,15 +238,15 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
+ input_report_abs(dev, ABS_PRESSURE, z);
+ input_report_key(dev, BTN_TOOL_FINGER, z > 0);
+
+- if (model->flags & ALPS_WHEEL)
++ if (priv->flags & ALPS_WHEEL)
+ input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07));
+
+- if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
++ if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+ input_report_key(dev, BTN_FORWARD, forward);
+ input_report_key(dev, BTN_BACK, back);
+ }
+
+- if (model->flags & ALPS_FOUR_BUTTONS) {
++ if (priv->flags & ALPS_FOUR_BUTTONS) {
+ input_report_key(dev, BTN_0, packet[2] & 4);
+ input_report_key(dev, BTN_1, packet[0] & 0x10);
+ input_report_key(dev, BTN_2, packet[3] & 4);
+@@ -699,9 +698,8 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
+ static void alps_process_packet(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+- const struct alps_model_info *model = priv->i;
+
+- switch (model->proto_version) {
++ switch (priv->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+ alps_process_packet_v1_v2(psmouse);
+@@ -765,7 +763,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
+ if (((psmouse->packet[3] |
+ psmouse->packet[4] |
+ psmouse->packet[5]) & 0x80) ||
+- (!alps_is_valid_first_byte(priv->i, psmouse->packet[6]))) {
++ (!alps_is_valid_first_byte(priv, psmouse->packet[6]))) {
+ psmouse_dbg(psmouse,
+ "refusing packet %4ph (suspected interleaved ps/2)\n",
+ psmouse->packet + 3);
+@@ -844,7 +842,6 @@ static void alps_flush_packet(unsigned long data)
+ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+- const struct alps_model_info *model = priv->i;
+
+ if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
+ if (psmouse->pktcnt == 3) {
+@@ -857,15 +854,15 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
+
+ /* Check for PS/2 packet stuffed in the middle of ALPS packet. */
+
+- if ((model->flags & ALPS_PS2_INTERLEAVED) &&
++ if ((priv->flags & ALPS_PS2_INTERLEAVED) &&
+ psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) {
+ return alps_handle_interleaved_ps2(psmouse);
+ }
+
+- if (!alps_is_valid_first_byte(model, psmouse->packet[0])) {
++ if (!alps_is_valid_first_byte(priv, psmouse->packet[0])) {
+ psmouse_dbg(psmouse,
+ "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
+- psmouse->packet[0], model->mask0, model->byte0);
++ psmouse->packet[0], priv->mask0, priv->byte0);
+ return PSMOUSE_BAD_DATA;
+ }
+
+@@ -1190,16 +1187,16 @@ static int alps_poll(struct psmouse *psmouse)
+ unsigned char buf[sizeof(psmouse->packet)];
+ bool poll_failed;
+
+- if (priv->i->flags & ALPS_PASS)
++ if (priv->flags & ALPS_PASS)
+ alps_passthrough_mode_v2(psmouse, true);
+
+ poll_failed = ps2_command(&psmouse->ps2dev, buf,
+ PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
+
+- if (priv->i->flags & ALPS_PASS)
++ if (priv->flags & ALPS_PASS)
+ alps_passthrough_mode_v2(psmouse, false);
+
+- if (poll_failed || (buf[0] & priv->i->mask0) != priv->i->byte0)
++ if (poll_failed || (buf[0] & priv->mask0) != priv->byte0)
+ return -1;
+
+ if ((psmouse->badbyte & 0xc8) == 0x08) {
+@@ -1217,9 +1214,8 @@ static int alps_poll(struct psmouse *psmouse)
+ static int alps_hw_init_v1_v2(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+- const struct alps_model_info *model = priv->i;
+
+- if ((model->flags & ALPS_PASS) &&
++ if ((priv->flags & ALPS_PASS) &&
+ alps_passthrough_mode_v2(psmouse, true)) {
+ return -1;
+ }
+@@ -1234,7 +1230,7 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)
+ return -1;
+ }
+
+- if ((model->flags & ALPS_PASS) &&
++ if ((priv->flags & ALPS_PASS) &&
+ alps_passthrough_mode_v2(psmouse, false)) {
+ return -1;
+ }
+@@ -1520,10 +1516,9 @@ error:
+ static int alps_hw_init(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+- const struct alps_model_info *model = priv->i;
+ int ret = -1;
+
+- switch (model->proto_version) {
++ switch (priv->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+ ret = alps_hw_init_v1_v2(psmouse);
+@@ -1585,7 +1580,10 @@ int alps_init(struct psmouse *psmouse)
+ if (!model)
+ goto init_fail;
+
+- priv->i = model;
++ priv->proto_version = model->proto_version;
++ priv->byte0 = model->byte0;
++ priv->mask0 = model->mask0;
++ priv->flags = model->flags;
+
+ if (alps_hw_init(psmouse))
+ goto init_fail;
+@@ -1609,7 +1607,7 @@ int alps_init(struct psmouse *psmouse)
+
+ dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
+
+- switch (model->proto_version) {
++ switch (priv->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+ input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
+@@ -1633,17 +1631,17 @@ int alps_init(struct psmouse *psmouse)
+
+ input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
+
+- if (model->flags & ALPS_WHEEL) {
++ if (priv->flags & ALPS_WHEEL) {
+ dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
+ dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL);
+ }
+
+- if (model->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
++ if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+ dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD);
+ dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK);
+ }
+
+- if (model->flags & ALPS_FOUR_BUTTONS) {
++ if (priv->flags & ALPS_FOUR_BUTTONS) {
+ dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0);
+ dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
+ dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
+@@ -1654,7 +1652,8 @@ int alps_init(struct psmouse *psmouse)
+
+ snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
+ dev2->phys = priv->phys;
+- dev2->name = (model->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
++ dev2->name = (priv->flags & ALPS_DUALPOINT) ?
++ "DualPoint Stick" : "PS/2 Mouse";
+ dev2->id.bustype = BUS_I8042;
+ dev2->id.vendor = 0x0002;
+ dev2->id.product = PSMOUSE_ALPS;
+@@ -1673,7 +1672,7 @@ int alps_init(struct psmouse *psmouse)
+ psmouse->poll = alps_poll;
+ psmouse->disconnect = alps_disconnect;
+ psmouse->reconnect = alps_reconnect;
+- psmouse->pktsize = model->proto_version == ALPS_PROTO_V4 ? 8 : 6;
++ psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6;
+
+ /* We are having trouble resyncing ALPS touchpads so disable it for now */
+ psmouse->resync_time = 0;
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index 67be4e5..efd0eea 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -63,10 +63,15 @@ struct alps_nibble_commands {
+ * struct alps_data - private data structure for the ALPS driver
+ * @dev2: "Relative" device used to report trackstick or mouse activity.
+ * @phys: Physical path for the relative device.
+- * @i: Information on the detected touchpad model.
+ * @nibble_commands: Command mapping used for touchpad register accesses.
+ * @addr_command: Command used to tell the touchpad that a register address
+ * follows.
++ * @proto_version: Indicates V1/V2/V3/...
++ * @byte0: Helps figure out whether a position report packet matches the
++ * known format for this model. The first byte of the report, ANDed with
++ * mask0, should match byte0.
++ * @mask0: The mask used to check the first byte of the report.
++ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ * @prev_fin: Finger bit from previous packet.
+ * @multi_packet: Multi-packet data in progress.
+ * @multi_data: Saved multi-packet data.
+@@ -81,9 +86,14 @@ struct alps_nibble_commands {
+ struct alps_data {
+ struct input_dev *dev2;
+ char phys[32];
+- const struct alps_model_info *i;
++
++ /* these are autodetected when the device is identified */
+ const struct alps_nibble_commands *nibble_commands;
+ int addr_command;
++ unsigned char proto_version;
++ unsigned char byte0, mask0;
++ unsigned char flags;
++
+ int prev_fin;
+ int multi_packet;
+ unsigned char multi_data[6];
+--
+1.8.1.2
+
+
+From b856c913996a38ced60bdf41aeae4da00882bf1f Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 20:57:04 -0800
+Subject: [PATCH 03/15] Input: ALPS - move alps_get_model() down below hw_init
+ code
+
+This will minimize the number of forward declarations needed when
+alps_get_model() starts assigning function pointers.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 186 ++++++++++++++++++++++-----------------------
+ 1 file changed, 93 insertions(+), 93 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 33ee6e0..c473549 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -998,99 +998,6 @@ static inline int alps_exit_command_mode(struct psmouse *psmouse)
+ return 0;
+ }
+
+-static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
+-{
+- struct ps2dev *ps2dev = &psmouse->ps2dev;
+- static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
+- unsigned char param[4];
+- const struct alps_model_info *model = NULL;
+- int i;
+-
+- /*
+- * First try "E6 report".
+- * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
+- * The bits 0-2 of the first byte will be 1s if some buttons are
+- * pressed.
+- */
+- param[0] = 0;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
+- return NULL;
+-
+- param[0] = param[1] = param[2] = 0xff;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+- return NULL;
+-
+- psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
+- param[0], param[1], param[2]);
+-
+- if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
+- (param[2] != 10 && param[2] != 100))
+- return NULL;
+-
+- /*
+- * Now try "E7 report". Allowed responses are in
+- * alps_model_data[].signature
+- */
+- param[0] = 0;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
+- return NULL;
+-
+- param[0] = param[1] = param[2] = 0xff;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+- return NULL;
+-
+- psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x",
+- param[0], param[1], param[2]);
+-
+- if (version) {
+- for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
+- /* empty */;
+- *version = (param[0] << 8) | (param[1] << 4) | i;
+- }
+-
+- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
+- if (!memcmp(param, alps_model_data[i].signature,
+- sizeof(alps_model_data[i].signature))) {
+- model = alps_model_data + i;
+- break;
+- }
+- }
+-
+- if (model && model->proto_version > ALPS_PROTO_V2) {
+- /*
+- * Need to check command mode response to identify
+- * model
+- */
+- model = NULL;
+- if (alps_enter_command_mode(psmouse, param)) {
+- psmouse_warn(psmouse,
+- "touchpad failed to enter command mode\n");
+- } else {
+- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
+- if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
+- alps_model_data[i].command_mode_resp == param[0]) {
+- model = alps_model_data + i;
+- break;
+- }
+- }
+- alps_exit_command_mode(psmouse);
+-
+- if (!model)
+- psmouse_dbg(psmouse,
+- "Unknown command mode response %2.2x\n",
+- param[0]);
+- }
+- }
+-
+- return model;
+-}
+-
+ /*
+ * For DualPoint devices select the device that should respond to
+ * subsequent commands. It looks like glidepad is behind stickpointer,
+@@ -1534,6 +1441,99 @@ static int alps_hw_init(struct psmouse *psmouse)
+ return ret;
+ }
+
++static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
++{
++ struct ps2dev *ps2dev = &psmouse->ps2dev;
++ static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
++ unsigned char param[4];
++ const struct alps_model_info *model = NULL;
++ int i;
++
++ /*
++ * First try "E6 report".
++ * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
++ * The bits 0-2 of the first byte will be 1s if some buttons are
++ * pressed.
++ */
++ param[0] = 0;
++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
++ return NULL;
++
++ param[0] = param[1] = param[2] = 0xff;
++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
++ return NULL;
++
++ psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
++ param[0], param[1], param[2]);
++
++ if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
++ (param[2] != 10 && param[2] != 100))
++ return NULL;
++
++ /*
++ * Now try "E7 report". Allowed responses are in
++ * alps_model_data[].signature
++ */
++ param[0] = 0;
++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
++ return NULL;
++
++ param[0] = param[1] = param[2] = 0xff;
++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
++ return NULL;
++
++ psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x",
++ param[0], param[1], param[2]);
++
++ if (version) {
++ for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
++ /* empty */;
++ *version = (param[0] << 8) | (param[1] << 4) | i;
++ }
++
++ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
++ if (!memcmp(param, alps_model_data[i].signature,
++ sizeof(alps_model_data[i].signature))) {
++ model = alps_model_data + i;
++ break;
++ }
++ }
++
++ if (model && model->proto_version > ALPS_PROTO_V2) {
++ /*
++ * Need to check command mode response to identify
++ * model
++ */
++ model = NULL;
++ if (alps_enter_command_mode(psmouse, param)) {
++ psmouse_warn(psmouse,
++ "touchpad failed to enter command mode\n");
++ } else {
++ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
++ if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
++ alps_model_data[i].command_mode_resp == param[0]) {
++ model = alps_model_data + i;
++ break;
++ }
++ }
++ alps_exit_command_mode(psmouse);
++
++ if (!model)
++ psmouse_dbg(psmouse,
++ "Unknown command mode response %2.2x\n",
++ param[0]);
++ }
++ }
++
++ return model;
++}
++
+ static int alps_reconnect(struct psmouse *psmouse)
+ {
+ const struct alps_model_info *model;
+--
+1.8.1.2
+
+
+From b719d56d5743e2c338568f4edb6eab17ea9c9eec Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:19:01 -0800
+Subject: [PATCH 04/15] Input: ALPS - introduce helper function for repeated
+ commands
+
+Several ALPS driver init sequences repeat a command three times, then
+issue PSMOUSE_CMD_GETINFO to read the result. Move this into a helper
+function to simplify the code.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 71 ++++++++++++++++++++--------------------------
+ 1 file changed, 30 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index c473549..1ca854b 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -964,24 +964,42 @@ static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr,
+ return __alps_command_mode_write_reg(psmouse, value);
+ }
+
++static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
++ int repeated_command, unsigned char *param)
++{
++ struct ps2dev *ps2dev = &psmouse->ps2dev;
++
++ param[0] = 0;
++ if (init_command && ps2_command(ps2dev, param, init_command))
++ return -EIO;
++
++ if (ps2_command(ps2dev, NULL, repeated_command) ||
++ ps2_command(ps2dev, NULL, repeated_command) ||
++ ps2_command(ps2dev, NULL, repeated_command))
++ return -EIO;
++
++ param[0] = param[1] = param[2] = 0xff;
++ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
++ return -EIO;
++
++ psmouse_dbg(psmouse, "%2.2X report: %2.2x %2.2x %2.2x\n",
++ repeated_command, param[0], param[1], param[2]);
++ return 0;
++}
++
+ static int alps_enter_command_mode(struct psmouse *psmouse,
+ unsigned char *resp)
+ {
+ unsigned char param[4];
+- struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
+- ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
++ if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_RESET_WRAP, param)) {
+ psmouse_err(psmouse, "failed to enter command mode\n");
+ return -1;
+ }
+
+ if (param[0] != 0x88 && param[1] != 0x07) {
+ psmouse_dbg(psmouse,
+- "unknown response while entering command mode: %2.2x %2.2x %2.2x\n",
+- param[0], param[1], param[2]);
++ "unknown response while entering command mode\n");
+ return -1;
+ }
+
+@@ -1041,18 +1059,10 @@ static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
+
+ static int alps_get_status(struct psmouse *psmouse, char *param)
+ {
+- struct ps2dev *ps2dev = &psmouse->ps2dev;
+-
+ /* Get status: 0xF5 0xF5 0xF5 0xE9 */
+- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
+- ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
++ if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_DISABLE, param))
+ return -1;
+
+- psmouse_dbg(psmouse, "Status: %2.2x %2.2x %2.2x",
+- param[0], param[1], param[2]);
+-
+ return 0;
+ }
+
+@@ -1443,7 +1453,6 @@ static int alps_hw_init(struct psmouse *psmouse)
+
+ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
+ {
+- struct ps2dev *ps2dev = &psmouse->ps2dev;
+ static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
+ unsigned char param[4];
+ const struct alps_model_info *model = NULL;
+@@ -1455,20 +1464,10 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
+ * The bits 0-2 of the first byte will be 1s if some buttons are
+ * pressed.
+ */
+- param[0] = 0;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
+- return NULL;
+-
+- param[0] = param[1] = param[2] = 0xff;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
++ if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, PSMOUSE_CMD_SETSCALE11,
++ param))
+ return NULL;
+
+- psmouse_dbg(psmouse, "E6 report: %2.2x %2.2x %2.2x",
+- param[0], param[1], param[2]);
+-
+ if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
+ (param[2] != 10 && param[2] != 100))
+ return NULL;
+@@ -1477,20 +1476,10 @@ static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int
+ * Now try "E7 report". Allowed responses are in
+ * alps_model_data[].signature
+ */
+- param[0] = 0;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
+- return NULL;
+-
+- param[0] = param[1] = param[2] = 0xff;
+- if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
++ if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, PSMOUSE_CMD_SETSCALE21,
++ param))
+ return NULL;
+
+- psmouse_dbg(psmouse, "E7 report: %2.2x %2.2x %2.2x",
+- param[0], param[1], param[2]);
+-
+ if (version) {
+ for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
+ /* empty */;
+--
+1.8.1.2
+
+
+From c7fd5d0e90f577072ece70651aeecb37f62f5fdb Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:19:59 -0800
+Subject: [PATCH 05/15] Input: ALPS - rework detection sequence
+
+If the E6 report test passes, get the E7 and EC reports right away and
+then try to match an entry in the table.
+
+Pass in the alps_data struct, so that the detection code will be able to
+set operating parameters based on information found during detection.
+
+Change the version (psmouse->model) to report the protocol version only,
+in preparation for supporting models that do not show up in the ID table.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 124 +++++++++++++++++++--------------------------
+ drivers/input/mouse/alps.h | 8 +--
+ 2 files changed, 56 insertions(+), 76 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 1ca854b..e6a27a5 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -1451,86 +1451,76 @@ static int alps_hw_init(struct psmouse *psmouse)
+ return ret;
+ }
+
+-static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
++static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
++ unsigned char *e7, unsigned char *ec)
+ {
+- static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
+- unsigned char param[4];
+- const struct alps_model_info *model = NULL;
++ const struct alps_model_info *model;
+ int i;
+
++ for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
++ model = &alps_model_data[i];
++
++ if (!memcmp(e7, model->signature, sizeof(model->signature)) &&
++ (!model->command_mode_resp ||
++ model->command_mode_resp == ec[2])) {
++
++ priv->proto_version = model->proto_version;
++ priv->flags = model->flags;
++ priv->byte0 = model->byte0;
++ priv->mask0 = model->mask0;
++
++ return 0;
++ }
++ }
++
++ return -EINVAL;
++}
++
++static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
++{
++ unsigned char e6[4], e7[4], ec[4];
++
+ /*
+ * First try "E6 report".
+ * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
+ * The bits 0-2 of the first byte will be 1s if some buttons are
+ * pressed.
+ */
+- if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, PSMOUSE_CMD_SETSCALE11,
+- param))
+- return NULL;
++ if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
++ PSMOUSE_CMD_SETSCALE11, e6))
++ return -EIO;
+
+- if ((param[0] & 0xf8) != 0 || param[1] != 0 ||
+- (param[2] != 10 && param[2] != 100))
+- return NULL;
++ if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100))
++ return -EINVAL;
+
+ /*
+- * Now try "E7 report". Allowed responses are in
+- * alps_model_data[].signature
++ * Now get the "E7" and "EC" reports. These will uniquely identify
++ * most ALPS touchpads.
+ */
+- if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, PSMOUSE_CMD_SETSCALE21,
+- param))
+- return NULL;
+-
+- if (version) {
+- for (i = 0; i < ARRAY_SIZE(rates) && param[2] != rates[i]; i++)
+- /* empty */;
+- *version = (param[0] << 8) | (param[1] << 4) | i;
+- }
+-
+- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
+- if (!memcmp(param, alps_model_data[i].signature,
+- sizeof(alps_model_data[i].signature))) {
+- model = alps_model_data + i;
+- break;
+- }
+- }
++ if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
++ PSMOUSE_CMD_SETSCALE21, e7) ||
++ alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
++ PSMOUSE_CMD_RESET_WRAP, ec) ||
++ alps_exit_command_mode(psmouse))
++ return -EIO;
+
+- if (model && model->proto_version > ALPS_PROTO_V2) {
+- /*
+- * Need to check command mode response to identify
+- * model
+- */
+- model = NULL;
+- if (alps_enter_command_mode(psmouse, param)) {
+- psmouse_warn(psmouse,
+- "touchpad failed to enter command mode\n");
+- } else {
+- for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
+- if (alps_model_data[i].proto_version > ALPS_PROTO_V2 &&
+- alps_model_data[i].command_mode_resp == param[0]) {
+- model = alps_model_data + i;
+- break;
+- }
+- }
+- alps_exit_command_mode(psmouse);
++ if (alps_match_table(psmouse, priv, e7, ec) == 0)
++ return 0;
+
+- if (!model)
+- psmouse_dbg(psmouse,
+- "Unknown command mode response %2.2x\n",
+- param[0]);
+- }
+- }
++ psmouse_info(psmouse,
++ "Unknown ALPS touchpad: E7=%2.2x %2.2x %2.2x, EC=%2.2x %2.2x %2.2x\n",
++ e7[0], e7[1], e7[2], ec[0], ec[1], ec[2]);
+
+- return model;
++ return -EINVAL;
+ }
+
+ static int alps_reconnect(struct psmouse *psmouse)
+ {
+- const struct alps_model_info *model;
++ struct alps_data *priv = psmouse->private;
+
+ psmouse_reset(psmouse);
+
+- model = alps_get_model(psmouse, NULL);
+- if (!model)
++ if (alps_identify(psmouse, priv) < 0)
+ return -1;
+
+ return alps_hw_init(psmouse);
+@@ -1549,9 +1539,7 @@ static void alps_disconnect(struct psmouse *psmouse)
+ int alps_init(struct psmouse *psmouse)
+ {
+ struct alps_data *priv;
+- const struct alps_model_info *model;
+ struct input_dev *dev1 = psmouse->dev, *dev2;
+- int version;
+
+ priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
+ dev2 = input_allocate_device();
+@@ -1565,15 +1553,9 @@ int alps_init(struct psmouse *psmouse)
+
+ psmouse_reset(psmouse);
+
+- model = alps_get_model(psmouse, &version);
+- if (!model)
++ if (alps_identify(psmouse, priv) < 0)
+ goto init_fail;
+
+- priv->proto_version = model->proto_version;
+- priv->byte0 = model->byte0;
+- priv->mask0 = model->mask0;
+- priv->flags = model->flags;
+-
+ if (alps_hw_init(psmouse))
+ goto init_fail;
+
+@@ -1678,18 +1660,16 @@ init_fail:
+
+ int alps_detect(struct psmouse *psmouse, bool set_properties)
+ {
+- int version;
+- const struct alps_model_info *model;
++ struct alps_data dummy;
+
+- model = alps_get_model(psmouse, &version);
+- if (!model)
++ if (alps_identify(psmouse, &dummy) < 0)
+ return -1;
+
+ if (set_properties) {
+ psmouse->vendor = "ALPS";
+- psmouse->name = model->flags & ALPS_DUALPOINT ?
++ psmouse->name = dummy.flags & ALPS_DUALPOINT ?
+ "DualPoint TouchPad" : "GlidePoint";
+- psmouse->model = version;
++ psmouse->model = dummy.proto_version << 8;
+ }
+ return 0;
+ }
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index efd0eea..a81b318 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -12,10 +12,10 @@
+ #ifndef _ALPS_H
+ #define _ALPS_H
+
+-#define ALPS_PROTO_V1 0
+-#define ALPS_PROTO_V2 1
+-#define ALPS_PROTO_V3 2
+-#define ALPS_PROTO_V4 3
++#define ALPS_PROTO_V1 1
++#define ALPS_PROTO_V2 2
++#define ALPS_PROTO_V3 3
++#define ALPS_PROTO_V4 4
+
+ /**
+ * struct alps_model_info - touchpad ID table
+--
+1.8.1.2
+
+
+From c7fb8a63ba1257e2ee829425ef7197c7cbe893a1 Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:22:08 -0800
+Subject: [PATCH 06/15] Input: ALPS - use function pointers for different
+ protocol handlers
+
+In anticipation of adding more ALPS protocols and more per-device quirks,
+use function pointers instead of switch statements to call functions that
+differ from one device to the next.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 101 +++++++++++++++++++++------------------------
+ drivers/input/mouse/alps.h | 7 ++++
+ 2 files changed, 54 insertions(+), 54 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index e6a27a5..fe45687 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -114,6 +114,11 @@ static const struct alps_model_info alps_model_data[] = {
+ { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
+ };
+
++static void alps_set_abs_params_st(struct alps_data *priv,
++ struct input_dev *dev1);
++static void alps_set_abs_params_mt(struct alps_data *priv,
++ struct input_dev *dev1);
++
+ /*
+ * XXX - this entry is suspicious. First byte has zero lower nibble,
+ * which is what a normal mouse would report. Also, the value 0x0e
+@@ -695,24 +700,6 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
+ input_sync(dev);
+ }
+
+-static void alps_process_packet(struct psmouse *psmouse)
+-{
+- struct alps_data *priv = psmouse->private;
+-
+- switch (priv->proto_version) {
+- case ALPS_PROTO_V1:
+- case ALPS_PROTO_V2:
+- alps_process_packet_v1_v2(psmouse);
+- break;
+- case ALPS_PROTO_V3:
+- alps_process_packet_v3(psmouse);
+- break;
+- case ALPS_PROTO_V4:
+- alps_process_packet_v4(psmouse);
+- break;
+- }
+-}
+-
+ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
+ unsigned char packet[],
+ bool report_buttons)
+@@ -770,7 +757,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
+ return PSMOUSE_BAD_DATA;
+ }
+
+- alps_process_packet(psmouse);
++ priv->process_packet(psmouse);
+
+ /* Continue with the next packet */
+ psmouse->packet[0] = psmouse->packet[6];
+@@ -814,6 +801,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
+ static void alps_flush_packet(unsigned long data)
+ {
+ struct psmouse *psmouse = (struct psmouse *)data;
++ struct alps_data *priv = psmouse->private;
+
+ serio_pause_rx(psmouse->ps2dev.serio);
+
+@@ -831,7 +819,7 @@ static void alps_flush_packet(unsigned long data)
+ "refusing packet %3ph (suspected interleaved ps/2)\n",
+ psmouse->packet + 3);
+ } else {
+- alps_process_packet(psmouse);
++ priv->process_packet(psmouse);
+ }
+ psmouse->pktcnt = 0;
+ }
+@@ -876,7 +864,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
+ }
+
+ if (psmouse->pktcnt == psmouse->pktsize) {
+- alps_process_packet(psmouse);
++ priv->process_packet(psmouse);
+ return PSMOUSE_FULL_PACKET;
+ }
+
+@@ -1430,25 +1418,26 @@ error:
+ return -1;
+ }
+
+-static int alps_hw_init(struct psmouse *psmouse)
++static void alps_set_defaults(struct alps_data *priv)
+ {
+- struct alps_data *priv = psmouse->private;
+- int ret = -1;
+-
+ switch (priv->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+- ret = alps_hw_init_v1_v2(psmouse);
++ priv->hw_init = alps_hw_init_v1_v2;
++ priv->process_packet = alps_process_packet_v1_v2;
++ priv->set_abs_params = alps_set_abs_params_st;
+ break;
+ case ALPS_PROTO_V3:
+- ret = alps_hw_init_v3(psmouse);
++ priv->hw_init = alps_hw_init_v3;
++ priv->process_packet = alps_process_packet_v3;
++ priv->set_abs_params = alps_set_abs_params_mt;
+ break;
+ case ALPS_PROTO_V4:
+- ret = alps_hw_init_v4(psmouse);
++ priv->hw_init = alps_hw_init_v4;
++ priv->process_packet = alps_process_packet_v4;
++ priv->set_abs_params = alps_set_abs_params_mt;
+ break;
+ }
+-
+- return ret;
+ }
+
+ static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
+@@ -1465,6 +1454,8 @@ static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
+ model->command_mode_resp == ec[2])) {
+
+ priv->proto_version = model->proto_version;
++ alps_set_defaults(priv);
++
+ priv->flags = model->flags;
+ priv->byte0 = model->byte0;
+ priv->mask0 = model->mask0;
+@@ -1523,7 +1514,7 @@ static int alps_reconnect(struct psmouse *psmouse)
+ if (alps_identify(psmouse, priv) < 0)
+ return -1;
+
+- return alps_hw_init(psmouse);
++ return priv->hw_init(psmouse);
+ }
+
+ static void alps_disconnect(struct psmouse *psmouse)
+@@ -1536,6 +1527,29 @@ static void alps_disconnect(struct psmouse *psmouse)
+ kfree(priv);
+ }
+
++static void alps_set_abs_params_st(struct alps_data *priv,
++ struct input_dev *dev1)
++{
++ input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
++ input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
++}
++
++static void alps_set_abs_params_mt(struct alps_data *priv,
++ struct input_dev *dev1)
++{
++ set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
++ input_mt_init_slots(dev1, 2, 0);
++ input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
++ input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
++
++ set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
++ set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
++ set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
++
++ input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
++ input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
++}
++
+ int alps_init(struct psmouse *psmouse)
+ {
+ struct alps_data *priv;
+@@ -1556,7 +1570,7 @@ int alps_init(struct psmouse *psmouse)
+ if (alps_identify(psmouse, priv) < 0)
+ goto init_fail;
+
+- if (alps_hw_init(psmouse))
++ if (priv->hw_init(psmouse))
+ goto init_fail;
+
+ /*
+@@ -1578,28 +1592,7 @@ int alps_init(struct psmouse *psmouse)
+
+ dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
+
+- switch (priv->proto_version) {
+- case ALPS_PROTO_V1:
+- case ALPS_PROTO_V2:
+- input_set_abs_params(dev1, ABS_X, 0, 1023, 0, 0);
+- input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
+- break;
+- case ALPS_PROTO_V3:
+- case ALPS_PROTO_V4:
+- set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+- input_mt_init_slots(dev1, 2, 0);
+- input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
+- input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
+-
+- set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
+- set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
+- set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
+-
+- input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
+- input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
+- break;
+- }
+-
++ priv->set_abs_params(priv, dev1);
+ input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
+
+ if (priv->flags & ALPS_WHEEL) {
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index a81b318..0934f8b 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -72,6 +72,9 @@ struct alps_nibble_commands {
+ * mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
++ * @hw_init: Protocol-specific hardware init function.
++ * @process_packet: Protocol-specific function to process a report packet.
++ * @set_abs_params: Protocol-specific function to configure the input_dev.
+ * @prev_fin: Finger bit from previous packet.
+ * @multi_packet: Multi-packet data in progress.
+ * @multi_data: Saved multi-packet data.
+@@ -94,6 +97,10 @@ struct alps_data {
+ unsigned char byte0, mask0;
+ unsigned char flags;
+
++ int (*hw_init)(struct psmouse *psmouse);
++ void (*process_packet)(struct psmouse *psmouse);
++ void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
++
+ int prev_fin;
+ int multi_packet;
+ unsigned char multi_data[6];
+--
+1.8.1.2
+
+
+From e2600c708bef8e1c8126ca9b8d4ce1f83c002688 Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:23:04 -0800
+Subject: [PATCH 07/15] Input: ALPS - move {addr,nibble}_command settings into
+ alps_set_defaults()
+
+This allows alps_identify() to override these settings based on the
+device characteristics, if it is ever necessary.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 12 ++++--------
+ 1 file changed, 4 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index fe45687..2221a00 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -1190,14 +1190,10 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
+
+ static int alps_hw_init_v3(struct psmouse *psmouse)
+ {
+- struct alps_data *priv = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int reg_val;
+ unsigned char param[4];
+
+- priv->nibble_commands = alps_v3_nibble_commands;
+- priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+-
+ if (alps_enter_command_mode(psmouse, NULL))
+ goto error;
+
+@@ -1343,13 +1339,9 @@ static int alps_absolute_mode_v4(struct psmouse *psmouse)
+
+ static int alps_hw_init_v4(struct psmouse *psmouse)
+ {
+- struct alps_data *priv = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+
+- priv->nibble_commands = alps_v4_nibble_commands;
+- priv->addr_command = PSMOUSE_CMD_DISABLE;
+-
+ if (alps_enter_command_mode(psmouse, NULL))
+ goto error;
+
+@@ -1431,11 +1423,15 @@ static void alps_set_defaults(struct alps_data *priv)
+ priv->hw_init = alps_hw_init_v3;
+ priv->process_packet = alps_process_packet_v3;
+ priv->set_abs_params = alps_set_abs_params_mt;
++ priv->nibble_commands = alps_v3_nibble_commands;
++ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+ break;
+ case ALPS_PROTO_V4:
+ priv->hw_init = alps_hw_init_v4;
+ priv->process_packet = alps_process_packet_v4;
+ priv->set_abs_params = alps_set_abs_params_mt;
++ priv->nibble_commands = alps_v4_nibble_commands;
++ priv->addr_command = PSMOUSE_CMD_DISABLE;
+ break;
+ }
+ }
+--
+1.8.1.2
+
+
+From df0bf385112a7b38c5c3d307bb9399f9f3b3bba2 Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:23:34 -0800
+Subject: [PATCH 08/15] Input: ALPS - rework detection of Pinnacle AGx
+ touchpads
+
+The official ALPS driver uses the EC report, not the E7 report, to detect
+these devices. Also, they check for a range of values; the original
+table-based code only checked for two specific ones.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 2221a00..eafeae2 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -109,8 +109,6 @@ static const struct alps_model_info alps_model_data[] = {
+ { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
+ { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
+- { { 0x73, 0x02, 0x64 }, 0x9b, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
+- { { 0x73, 0x02, 0x64 }, 0x9d, ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT },
+ { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
+ };
+
+@@ -1412,6 +1410,10 @@ error:
+
+ static void alps_set_defaults(struct alps_data *priv)
+ {
++ priv->byte0 = 0x8f;
++ priv->mask0 = 0x8f;
++ priv->flags = ALPS_DUALPOINT;
++
+ switch (priv->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+@@ -1491,8 +1493,15 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
+ alps_exit_command_mode(psmouse))
+ return -EIO;
+
+- if (alps_match_table(psmouse, priv, e7, ec) == 0)
++ if (alps_match_table(psmouse, priv, e7, ec) == 0) {
++ return 0;
++ } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
++ ec[2] >= 0x90 && ec[2] <= 0x9d) {
++ priv->proto_version = ALPS_PROTO_V3;
++ alps_set_defaults(priv);
++
+ return 0;
++ }
+
+ psmouse_info(psmouse,
+ "Unknown ALPS touchpad: E7=%2.2x %2.2x %2.2x, EC=%2.2x %2.2x %2.2x\n",
+--
+1.8.1.2
+
+
+From 8e6493f800dc08a28abd59dfe63790aaade0c700 Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:24:22 -0800
+Subject: [PATCH 09/15] Input: ALPS - fix command mode check
+
+Pinnacle class devices should return "88 07 xx" or "88 08 xx" when
+entering command mode. If either the first byte or the second byte is
+invalid, return an error.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index eafeae2..bfc1938 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -983,7 +983,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse,
+ return -1;
+ }
+
+- if (param[0] != 0x88 && param[1] != 0x07) {
++ if (param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) {
+ psmouse_dbg(psmouse,
+ "unknown response while entering command mode\n");
+ return -1;
+--
+1.8.1.2
+
+
+From 0302b4c4a1b4201bf82a45c46084f3ccd0ee696f Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:24:55 -0800
+Subject: [PATCH 10/15] Input: ALPS - move pixel and bitmap info into alps_data
+ struct
+
+Newer touchpads use different constants, so make them runtime-
+configurable.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 47 ++++++++++++++++++++++++----------------------
+ drivers/input/mouse/alps.h | 8 ++++++++
+ 2 files changed, 33 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index bfc1938..2cd8be7 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -27,12 +27,6 @@
+ /*
+ * Definitions for ALPS version 3 and 4 command mode protocol
+ */
+-#define ALPS_V3_X_MAX 2000
+-#define ALPS_V3_Y_MAX 1400
+-
+-#define ALPS_BITMAP_X_BITS 15
+-#define ALPS_BITMAP_Y_BITS 11
+-
+ #define ALPS_CMD_NIBBLE_10 0x01f2
+
+ static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
+@@ -269,7 +263,8 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
+ * These points are returned in x1, y1, x2, and y2 when the return value
+ * is greater than 0.
+ */
+-static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
++static int alps_process_bitmap(struct alps_data *priv,
++ unsigned int x_map, unsigned int y_map,
+ int *x1, int *y1, int *x2, int *y2)
+ {
+ struct alps_bitmap_point {
+@@ -311,7 +306,7 @@ static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
+ * y bitmap is reversed for what we need (lower positions are in
+ * higher bits), so we process from the top end.
+ */
+- y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - ALPS_BITMAP_Y_BITS);
++ y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
+ prev_bit = 0;
+ point = &y_low;
+ for (i = 0; y_map != 0; i++, y_map <<= 1) {
+@@ -357,16 +352,18 @@ static int alps_process_bitmap(unsigned int x_map, unsigned int y_map,
+ }
+ }
+
+- *x1 = (ALPS_V3_X_MAX * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+- (2 * (ALPS_BITMAP_X_BITS - 1));
+- *y1 = (ALPS_V3_Y_MAX * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+- (2 * (ALPS_BITMAP_Y_BITS - 1));
++ *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
++ (2 * (priv->x_bits - 1));
++ *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
++ (2 * (priv->y_bits - 1));
+
+ if (fingers > 1) {
+- *x2 = (ALPS_V3_X_MAX * (2 * x_high.start_bit + x_high.num_bits - 1)) /
+- (2 * (ALPS_BITMAP_X_BITS - 1));
+- *y2 = (ALPS_V3_Y_MAX * (2 * y_high.start_bit + y_high.num_bits - 1)) /
+- (2 * (ALPS_BITMAP_Y_BITS - 1));
++ *x2 = (priv->x_max *
++ (2 * x_high.start_bit + x_high.num_bits - 1)) /
++ (2 * (priv->x_bits - 1));
++ *y2 = (priv->y_max *
++ (2 * y_high.start_bit + y_high.num_bits - 1)) /
++ (2 * (priv->y_bits - 1));
+ }
+
+ return fingers;
+@@ -484,7 +481,8 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ ((packet[2] & 0x7f) << 1) |
+ (packet[4] & 0x01);
+
+- bmap_fingers = alps_process_bitmap(x_bitmap, y_bitmap,
++ bmap_fingers = alps_process_bitmap(priv,
++ x_bitmap, y_bitmap,
+ &x1, &y1, &x2, &y2);
+
+ /*
+@@ -641,7 +639,7 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
+ ((priv->multi_data[3] & 0x1f) << 5) |
+ (priv->multi_data[1] & 0x1f);
+
+- fingers = alps_process_bitmap(x_bitmap, y_bitmap,
++ fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
+ &x1, &y1, &x2, &y2);
+
+ /* Store MT data.*/
+@@ -1414,6 +1412,11 @@ static void alps_set_defaults(struct alps_data *priv)
+ priv->mask0 = 0x8f;
+ priv->flags = ALPS_DUALPOINT;
+
++ priv->x_max = 2000;
++ priv->y_max = 1400;
++ priv->x_bits = 15;
++ priv->y_bits = 11;
++
+ switch (priv->proto_version) {
+ case ALPS_PROTO_V1:
+ case ALPS_PROTO_V2:
+@@ -1544,15 +1547,15 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
+ {
+ set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+ input_mt_init_slots(dev1, 2, 0);
+- input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
+- input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, ALPS_V3_Y_MAX, 0, 0);
++ input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
++ input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
+
+ set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
+ set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
+ set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
+
+- input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
+- input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
++ input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
++ input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
+ }
+
+ int alps_init(struct psmouse *psmouse)
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index 0934f8b..5e638be 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -72,6 +72,10 @@ struct alps_nibble_commands {
+ * mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
++ * @x_max: Largest possible X position value.
++ * @y_max: Largest possible Y position value.
++ * @x_bits: Number of X bits in the MT bitmap.
++ * @y_bits: Number of Y bits in the MT bitmap.
+ * @hw_init: Protocol-specific hardware init function.
+ * @process_packet: Protocol-specific function to process a report packet.
+ * @set_abs_params: Protocol-specific function to configure the input_dev.
+@@ -96,6 +100,10 @@ struct alps_data {
+ unsigned char proto_version;
+ unsigned char byte0, mask0;
+ unsigned char flags;
++ int x_max;
++ int y_max;
++ int x_bits;
++ int y_bits;
+
+ int (*hw_init)(struct psmouse *psmouse);
+ void (*process_packet)(struct psmouse *psmouse);
+--
+1.8.1.2
+
+
+From 3c9d054fef84ccc967445b330ab6012c6b6bd85b Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:26:11 -0800
+Subject: [PATCH 11/15] Input: ALPS - make the V3 packet field decoder
+ "pluggable"
+
+A number of different ALPS touchpad protocols can reuse
+alps_process_touchpad_packet_v3() with small tweaks to the bitfield
+decoding. Create a new priv->decode_fields() callback that handles the
+per-model differences.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 101 +++++++++++++++++++++++++--------------------
+ drivers/input/mouse/alps.h | 38 +++++++++++++++++
+ 2 files changed, 95 insertions(+), 44 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 2cd8be7..270b7de 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -447,17 +447,49 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
+ return;
+ }
+
++static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
++{
++ f->left = !!(p[3] & 0x01);
++ f->right = !!(p[3] & 0x02);
++ f->middle = !!(p[3] & 0x04);
++
++ f->ts_left = !!(p[3] & 0x10);
++ f->ts_right = !!(p[3] & 0x20);
++ f->ts_middle = !!(p[3] & 0x40);
++}
++
++static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
++{
++ f->first_mp = !!(p[4] & 0x40);
++ f->is_mp = !!(p[0] & 0x40);
++
++ f->fingers = (p[5] & 0x3) + 1;
++ f->x_map = ((p[4] & 0x7e) << 8) |
++ ((p[1] & 0x7f) << 2) |
++ ((p[0] & 0x30) >> 4);
++ f->y_map = ((p[3] & 0x70) << 4) |
++ ((p[2] & 0x7f) << 1) |
++ (p[4] & 0x01);
++
++ f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
++ ((p[0] & 0x30) >> 4);
++ f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
++ f->z = p[5] & 0x7f;
++
++ alps_decode_buttons_v3(f, p);
++}
++
+ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ struct input_dev *dev2 = priv->dev2;
+- int x, y, z;
+- int left, right, middle;
+ int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+ int fingers = 0, bmap_fingers;
+- unsigned int x_bitmap, y_bitmap;
++ struct alps_fields f;
++
++ priv->decode_fields(&f, packet);
+
+ /*
+ * There's no single feature of touchpad position and bitmap packets
+@@ -472,17 +504,10 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ * packet. Check for this, and when it happens process the
+ * position packet as usual.
+ */
+- if (packet[0] & 0x40) {
+- fingers = (packet[5] & 0x3) + 1;
+- x_bitmap = ((packet[4] & 0x7e) << 8) |
+- ((packet[1] & 0x7f) << 2) |
+- ((packet[0] & 0x30) >> 4);
+- y_bitmap = ((packet[3] & 0x70) << 4) |
+- ((packet[2] & 0x7f) << 1) |
+- (packet[4] & 0x01);
+-
++ if (f.is_mp) {
++ fingers = f.fingers;
+ bmap_fingers = alps_process_bitmap(priv,
+- x_bitmap, y_bitmap,
++ f.x_map, f.y_map,
+ &x1, &y1, &x2, &y2);
+
+ /*
+@@ -493,7 +518,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ fingers = bmap_fingers;
+
+ /* Now process position packet */
+- packet = priv->multi_data;
++ priv->decode_fields(&f, priv->multi_data);
+ } else {
+ priv->multi_packet = 0;
+ }
+@@ -507,10 +532,10 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ * out misidentified bitmap packets, we reject anything with this
+ * bit set.
+ */
+- if (packet[0] & 0x40)
++ if (f.is_mp)
+ return;
+
+- if (!priv->multi_packet && (packet[4] & 0x40)) {
++ if (!priv->multi_packet && f.first_mp) {
+ priv->multi_packet = 1;
+ memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
+ return;
+@@ -518,22 +543,13 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+
+ priv->multi_packet = 0;
+
+- left = packet[3] & 0x01;
+- right = packet[3] & 0x02;
+- middle = packet[3] & 0x04;
+-
+- x = ((packet[1] & 0x7f) << 4) | ((packet[4] & 0x30) >> 2) |
+- ((packet[0] & 0x30) >> 4);
+- y = ((packet[2] & 0x7f) << 4) | (packet[4] & 0x0f);
+- z = packet[5] & 0x7f;
+-
+ /*
+ * Sometimes the hardware sends a single packet with z = 0
+ * in the middle of a stream. Real releases generate packets
+ * with x, y, and z all zero, so these seem to be flukes.
+ * Ignore them.
+ */
+- if (x && y && !z)
++ if (f.x && f.y && !f.z)
+ return;
+
+ /*
+@@ -541,12 +557,12 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ * to rely on ST data.
+ */
+ if (!fingers) {
+- x1 = x;
+- y1 = y;
+- fingers = z > 0 ? 1 : 0;
++ x1 = f.x;
++ y1 = f.y;
++ fingers = f.z > 0 ? 1 : 0;
+ }
+
+- if (z >= 64)
++ if (f.z >= 64)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+@@ -555,26 +571,22 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+
+ input_mt_report_finger_count(dev, fingers);
+
+- input_report_key(dev, BTN_LEFT, left);
+- input_report_key(dev, BTN_RIGHT, right);
+- input_report_key(dev, BTN_MIDDLE, middle);
++ input_report_key(dev, BTN_LEFT, f.left);
++ input_report_key(dev, BTN_RIGHT, f.right);
++ input_report_key(dev, BTN_MIDDLE, f.middle);
+
+- if (z > 0) {
+- input_report_abs(dev, ABS_X, x);
+- input_report_abs(dev, ABS_Y, y);
++ if (f.z > 0) {
++ input_report_abs(dev, ABS_X, f.x);
++ input_report_abs(dev, ABS_Y, f.y);
+ }
+- input_report_abs(dev, ABS_PRESSURE, z);
++ input_report_abs(dev, ABS_PRESSURE, f.z);
+
+ input_sync(dev);
+
+ if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
+- left = packet[3] & 0x10;
+- right = packet[3] & 0x20;
+- middle = packet[3] & 0x40;
+-
+- input_report_key(dev2, BTN_LEFT, left);
+- input_report_key(dev2, BTN_RIGHT, right);
+- input_report_key(dev2, BTN_MIDDLE, middle);
++ input_report_key(dev2, BTN_LEFT, f.ts_left);
++ input_report_key(dev2, BTN_RIGHT, f.ts_right);
++ input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
+ input_sync(dev2);
+ }
+ }
+@@ -1428,6 +1440,7 @@ static void alps_set_defaults(struct alps_data *priv)
+ priv->hw_init = alps_hw_init_v3;
+ priv->process_packet = alps_process_packet_v3;
+ priv->set_abs_params = alps_set_abs_params_mt;
++ priv->decode_fields = alps_decode_pinnacle;
+ priv->nibble_commands = alps_v3_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+ break;
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index 5e638be..9704805 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -60,6 +60,42 @@ struct alps_nibble_commands {
+ };
+
+ /**
++ * struct alps_fields - decoded version of the report packet
++ * @x_map: Bitmap of active X positions for MT.
++ * @y_map: Bitmap of active Y positions for MT.
++ * @fingers: Number of fingers for MT.
++ * @x: X position for ST.
++ * @y: Y position for ST.
++ * @z: Z position for ST.
++ * @first_mp: Packet is the first of a multi-packet report.
++ * @is_mp: Packet is part of a multi-packet report.
++ * @left: Left touchpad button is active.
++ * @right: Right touchpad button is active.
++ * @middle: Middle touchpad button is active.
++ * @ts_left: Left trackstick button is active.
++ * @ts_right: Right trackstick button is active.
++ * @ts_middle: Middle trackstick button is active.
++ */
++struct alps_fields {
++ unsigned int x_map;
++ unsigned int y_map;
++ unsigned int fingers;
++ unsigned int x;
++ unsigned int y;
++ unsigned int z;
++ unsigned int first_mp:1;
++ unsigned int is_mp:1;
++
++ unsigned int left:1;
++ unsigned int right:1;
++ unsigned int middle:1;
++
++ unsigned int ts_left:1;
++ unsigned int ts_right:1;
++ unsigned int ts_middle:1;
++};
++
++/**
+ * struct alps_data - private data structure for the ALPS driver
+ * @dev2: "Relative" device used to report trackstick or mouse activity.
+ * @phys: Physical path for the relative device.
+@@ -78,6 +114,7 @@ struct alps_nibble_commands {
+ * @y_bits: Number of Y bits in the MT bitmap.
+ * @hw_init: Protocol-specific hardware init function.
+ * @process_packet: Protocol-specific function to process a report packet.
++ * @decode_fields: Protocol-specific function to read packet bitfields.
+ * @set_abs_params: Protocol-specific function to configure the input_dev.
+ * @prev_fin: Finger bit from previous packet.
+ * @multi_packet: Multi-packet data in progress.
+@@ -107,6 +144,7 @@ struct alps_data {
+
+ int (*hw_init)(struct psmouse *psmouse);
+ void (*process_packet)(struct psmouse *psmouse);
++ void (*decode_fields)(struct alps_fields *f, unsigned char *p);
+ void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
+
+ int prev_fin;
+--
+1.8.1.2
+
+
+From 9e7c99b6c125653f53ef0999a176c3a79de21be8 Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:27:08 -0800
+Subject: [PATCH 12/15] Input: ALPS - add support for "Rushmore" touchpads
+
+Rushmore touchpads are found on Dell E6230/E6430/E6530. They use the V3
+protocol with slightly tweaked init sequences and report formats.
+
+The E7 report is 73 03 0a, and the EC report is 88 08 1d
+
+Credits: Emmanuel Thome reported the MT bitmap changes.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 270b7de..bf2fa51 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -479,6 +479,14 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p)
+ alps_decode_buttons_v3(f, p);
+ }
+
++static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
++{
++ alps_decode_pinnacle(f, p);
++
++ f->x_map |= (p[5] & 0x10) << 11;
++ f->y_map |= (p[5] & 0x20) << 6;
++}
++
+ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+@@ -1329,6 +1337,40 @@ error:
+ return -1;
+ }
+
++static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
++{
++ struct ps2dev *ps2dev = &psmouse->ps2dev;
++ int reg_val, ret = -1;
++
++ if (alps_enter_command_mode(psmouse, NULL) ||
++ alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 ||
++ alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
++ goto error;
++
++ reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
++ if (reg_val == -1)
++ goto error;
++ if (__alps_command_mode_write_reg(psmouse, reg_val & 0xfd))
++ goto error;
++
++ if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
++ goto error;
++
++ /* enter absolute mode */
++ reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
++ if (reg_val == -1)
++ goto error;
++ if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
++ goto error;
++
++ alps_exit_command_mode(psmouse);
++ return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
++
++error:
++ alps_exit_command_mode(psmouse);
++ return ret;
++}
++
+ /* Must be in command mode when calling this function */
+ static int alps_absolute_mode_v4(struct psmouse *psmouse)
+ {
+@@ -1511,6 +1553,16 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
+
+ if (alps_match_table(psmouse, priv, e7, ec) == 0) {
+ return 0;
++ } else if (ec[0] == 0x88 && ec[1] == 0x08) {
++ priv->proto_version = ALPS_PROTO_V3;
++ alps_set_defaults(priv);
++
++ priv->hw_init = alps_hw_init_rushmore_v3;
++ priv->decode_fields = alps_decode_rushmore;
++ priv->x_bits = 16;
++ priv->y_bits = 12;
++
++ return 0;
+ } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
+ ec[2] >= 0x90 && ec[2] <= 0x9d) {
+ priv->proto_version = ALPS_PROTO_V3;
+--
+1.8.1.2
+
+
+From e5ca58dc506fb7f64760b483ecd407593b764f3b Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Wed, 13 Feb 2013 22:28:07 -0800
+Subject: [PATCH 13/15] Input: ALPS - enable trackstick on Rushmore touchpads
+
+Separate out the common trackstick probe/setup sequences, then call them
+from each of the v3 init functions.
+
+Credits: Emmanual Thome furnished the information on the trackstick init
+and how it affected the report format.
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+Tested-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+---
+ drivers/input/mouse/alps.c | 185 ++++++++++++++++++++++++++++-----------------
+ 1 file changed, 115 insertions(+), 70 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index bf2fa51..7b99fc7 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -29,6 +29,9 @@
+ */
+ #define ALPS_CMD_NIBBLE_10 0x01f2
+
++#define ALPS_REG_BASE_RUSHMORE 0xc2c0
++#define ALPS_REG_BASE_PINNACLE 0x0000
++
+ static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
+ { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
+ { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
+@@ -1166,26 +1169,31 @@ static int alps_hw_init_v1_v2(struct psmouse *psmouse)
+ }
+
+ /*
+- * Enable or disable passthrough mode to the trackstick. Must be in
+- * command mode when calling this function.
++ * Enable or disable passthrough mode to the trackstick.
+ */
+-static int alps_passthrough_mode_v3(struct psmouse *psmouse, bool enable)
++static int alps_passthrough_mode_v3(struct psmouse *psmouse,
++ int reg_base, bool enable)
+ {
+- int reg_val;
++ int reg_val, ret = -1;
+
+- reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
+- if (reg_val == -1)
++ if (alps_enter_command_mode(psmouse, NULL))
+ return -1;
+
++ reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008);
++ if (reg_val == -1)
++ goto error;
++
+ if (enable)
+ reg_val |= 0x01;
+ else
+ reg_val &= ~0x01;
+
+- if (__alps_command_mode_write_reg(psmouse, reg_val))
+- return -1;
++ ret = __alps_command_mode_write_reg(psmouse, reg_val);
+
+- return 0;
++error:
++ if (alps_exit_command_mode(psmouse))
++ ret = -1;
++ return ret;
+ }
+
+ /* Must be in command mode when calling this function */
+@@ -1204,69 +1212,102 @@ static int alps_absolute_mode_v3(struct psmouse *psmouse)
+ return 0;
+ }
+
+-static int alps_hw_init_v3(struct psmouse *psmouse)
++static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base)
+ {
+- struct ps2dev *ps2dev = &psmouse->ps2dev;
+- int reg_val;
+- unsigned char param[4];
++ int ret = -EIO, reg_val;
+
+ if (alps_enter_command_mode(psmouse, NULL))
+ goto error;
+
+- /* Check for trackstick */
+- reg_val = alps_command_mode_read_reg(psmouse, 0x0008);
++ reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08);
+ if (reg_val == -1)
+ goto error;
+- if (reg_val & 0x80) {
+- if (alps_passthrough_mode_v3(psmouse, true))
+- goto error;
+- if (alps_exit_command_mode(psmouse))
+- goto error;
++
++ /* bit 7: trackstick is present */
++ ret = reg_val & 0x80 ? 0 : -ENODEV;
++
++error:
++ alps_exit_command_mode(psmouse);
++ return ret;
++}
++
++static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
++{
++ struct ps2dev *ps2dev = &psmouse->ps2dev;
++ int ret = 0;
++ unsigned char param[4];
++
++ if (alps_passthrough_mode_v3(psmouse, reg_base, true))
++ return -EIO;
++
++ /*
++ * E7 report for the trackstick
++ *
++ * There have been reports of failures to seem to trace back
++ * to the above trackstick check failing. When these occur
++ * this E7 report fails, so when that happens we continue
++ * with the assumption that there isn't a trackstick after
++ * all.
++ */
++ if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) {
++ psmouse_warn(psmouse, "trackstick E7 report failed\n");
++ ret = -ENODEV;
++ } else {
++ psmouse_dbg(psmouse,
++ "trackstick E7 report: %2.2x %2.2x %2.2x\n",
++ param[0], param[1], param[2]);
+
+ /*
+- * E7 report for the trackstick
+- *
+- * There have been reports of failures to seem to trace back
+- * to the above trackstick check failing. When these occur
+- * this E7 report fails, so when that happens we continue
+- * with the assumption that there isn't a trackstick after
+- * all.
++ * Not sure what this does, but it is absolutely
++ * essential. Without it, the touchpad does not
++ * work at all and the trackstick just emits normal
++ * PS/2 packets.
+ */
+- param[0] = 0x64;
+- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
+- ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
+- psmouse_warn(psmouse, "trackstick E7 report failed\n");
+- } else {
+- psmouse_dbg(psmouse,
+- "trackstick E7 report: %2.2x %2.2x %2.2x\n",
+- param[0], param[1], param[2]);
+-
+- /*
+- * Not sure what this does, but it is absolutely
+- * essential. Without it, the touchpad does not
+- * work at all and the trackstick just emits normal
+- * PS/2 packets.
+- */
+- if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+- ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
+- alps_command_mode_send_nibble(psmouse, 0x9) ||
+- alps_command_mode_send_nibble(psmouse, 0x4)) {
+- psmouse_err(psmouse,
+- "Error sending magic E6 sequence\n");
+- goto error_passthrough;
+- }
++ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
++ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
++ alps_command_mode_send_nibble(psmouse, 0x9) ||
++ alps_command_mode_send_nibble(psmouse, 0x4)) {
++ psmouse_err(psmouse,
++ "Error sending magic E6 sequence\n");
++ ret = -EIO;
++ goto error;
+ }
+
+- if (alps_enter_command_mode(psmouse, NULL))
+- goto error_passthrough;
+- if (alps_passthrough_mode_v3(psmouse, false))
+- goto error;
++ /*
++ * This ensures the trackstick packets are in the format
++ * supported by this driver. If bit 1 isn't set the packet
++ * format is different.
++ */
++ if (alps_enter_command_mode(psmouse, NULL) ||
++ alps_command_mode_write_reg(psmouse,
++ reg_base + 0x08, 0x82) ||
++ alps_exit_command_mode(psmouse))
++ ret = -EIO;
+ }
+
+- if (alps_absolute_mode_v3(psmouse)) {
++error:
++ if (alps_passthrough_mode_v3(psmouse, reg_base, false))
++ ret = -EIO;
++
++ return ret;
++}
++
++static int alps_hw_init_v3(struct psmouse *psmouse)
++{
++ struct ps2dev *ps2dev = &psmouse->ps2dev;
++ int reg_val;
++ unsigned char param[4];
++
++ reg_val = alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE);
++ if (reg_val == -EIO)
++ goto error;
++ if (reg_val == 0 &&
++ alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
++ goto error;
++
++ if (alps_enter_command_mode(psmouse, NULL) ||
++ alps_absolute_mode_v3(psmouse)) {
+ psmouse_err(psmouse, "Failed to enter absolute mode\n");
+ goto error;
+ }
+@@ -1303,14 +1344,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse)
+ if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
+ goto error;
+
+- /*
+- * This ensures the trackstick packets are in the format
+- * supported by this driver. If bit 1 isn't set the packet
+- * format is different.
+- */
+- if (alps_command_mode_write_reg(psmouse, 0x0008, 0x82))
+- goto error;
+-
+ alps_exit_command_mode(psmouse);
+
+ /* Set rate and enable data reporting */
+@@ -1323,10 +1356,6 @@ static int alps_hw_init_v3(struct psmouse *psmouse)
+
+ return 0;
+
+-error_passthrough:
+- /* Something failed while in passthrough mode, so try to get out */
+- if (!alps_enter_command_mode(psmouse, NULL))
+- alps_passthrough_mode_v3(psmouse, false);
+ error:
+ /*
+ * Leaving the touchpad in command mode will essentially render
+@@ -1339,9 +1368,19 @@ error:
+
+ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
+ {
++ struct alps_data *priv = psmouse->private;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int reg_val, ret = -1;
+
++ if (priv->flags & ALPS_DUALPOINT) {
++ reg_val = alps_setup_trackstick_v3(psmouse,
++ ALPS_REG_BASE_RUSHMORE);
++ if (reg_val == -EIO)
++ goto error;
++ if (reg_val == -ENODEV)
++ priv->flags &= ~ALPS_DUALPOINT;
++ }
++
+ if (alps_enter_command_mode(psmouse, NULL) ||
+ alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 ||
+ alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
+@@ -1562,6 +1601,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
+ priv->x_bits = 16;
+ priv->y_bits = 12;
+
++ /* hack to make addr_command, nibble_command available */
++ psmouse->private = priv;
++
++ if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE))
++ priv->flags &= ~ALPS_DUALPOINT;
++
+ return 0;
+ } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
+ ec[2] >= 0x90 && ec[2] <= 0x9d) {
+--
+1.8.1.2
+
+
+From db7192fa07fa5c70c9849d8f658a7ff696cff99d Mon Sep 17 00:00:00 2001
+From: Kevin Cernekee <cernekee@gmail.com>
+Date: Sat, 16 Feb 2013 22:40:03 -0800
+Subject: [PATCH 14/15] Input: ALPS - Remove unused argument to
+ alps_enter_command_mode()
+
+Now that alps_identify() explicitly issues an EC report using
+alps_rpt_cmd(), we no longer need to look at the magic numbers returned
+by alps_enter_command_mode().
+
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+---
+ drivers/input/mouse/alps.c | 18 +++++++-----------
+ 1 file changed, 7 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 7b99fc7..9c97531 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -994,8 +994,7 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
+ return 0;
+ }
+
+-static int alps_enter_command_mode(struct psmouse *psmouse,
+- unsigned char *resp)
++static int alps_enter_command_mode(struct psmouse *psmouse)
+ {
+ unsigned char param[4];
+
+@@ -1009,9 +1008,6 @@ static int alps_enter_command_mode(struct psmouse *psmouse,
+ "unknown response while entering command mode\n");
+ return -1;
+ }
+-
+- if (resp)
+- *resp = param[2];
+ return 0;
+ }
+
+@@ -1176,7 +1172,7 @@ static int alps_passthrough_mode_v3(struct psmouse *psmouse,
+ {
+ int reg_val, ret = -1;
+
+- if (alps_enter_command_mode(psmouse, NULL))
++ if (alps_enter_command_mode(psmouse))
+ return -1;
+
+ reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008);
+@@ -1216,7 +1212,7 @@ static int alps_probe_trackstick_v3(struct psmouse *psmouse, int reg_base)
+ {
+ int ret = -EIO, reg_val;
+
+- if (alps_enter_command_mode(psmouse, NULL))
++ if (alps_enter_command_mode(psmouse))
+ goto error;
+
+ reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08);
+@@ -1279,7 +1275,7 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
+ * supported by this driver. If bit 1 isn't set the packet
+ * format is different.
+ */
+- if (alps_enter_command_mode(psmouse, NULL) ||
++ if (alps_enter_command_mode(psmouse) ||
+ alps_command_mode_write_reg(psmouse,
+ reg_base + 0x08, 0x82) ||
+ alps_exit_command_mode(psmouse))
+@@ -1306,7 +1302,7 @@ static int alps_hw_init_v3(struct psmouse *psmouse)
+ alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
+ goto error;
+
+- if (alps_enter_command_mode(psmouse, NULL) ||
++ if (alps_enter_command_mode(psmouse) ||
+ alps_absolute_mode_v3(psmouse)) {
+ psmouse_err(psmouse, "Failed to enter absolute mode\n");
+ goto error;
+@@ -1381,7 +1377,7 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
+ priv->flags &= ~ALPS_DUALPOINT;
+ }
+
+- if (alps_enter_command_mode(psmouse, NULL) ||
++ if (alps_enter_command_mode(psmouse) ||
+ alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 ||
+ alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
+ goto error;
+@@ -1431,7 +1427,7 @@ static int alps_hw_init_v4(struct psmouse *psmouse)
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+
+- if (alps_enter_command_mode(psmouse, NULL))
++ if (alps_enter_command_mode(psmouse))
+ goto error;
+
+ if (alps_absolute_mode_v4(psmouse)) {
+--
+1.8.1.2
+
+
+From 10740a25bb3b895b5de7773f926a978416b38409 Mon Sep 17 00:00:00 2001
+From: Dave Turvene <dturvene@dahetral.com>
+Date: Sat, 16 Feb 2013 22:40:04 -0800
+Subject: [PATCH 15/15] Input: ALPS - Add "Dolphin V1" touchpad support
+
+These touchpads use a different protocol; they have been seen on Dell
+N5110, Dell 17R SE, and others.
+
+The official ALPS driver identifies them by looking for an exact match
+on the E7 report: 73 03 50. Dolphin V1 returns an EC report of
+73 01 xx (02 and 0d have been seen); Dolphin V2 returns an EC report of
+73 02 xx (02 has been seen).
+
+Dolphin V2 probably needs a different initialization sequence and/or
+report parser, so it is left for a future commit.
+
+Signed-off-by: Dave Turvene <dturvene@dahetral.com>
+Signed-off-by: Kevin Cernekee <cernekee@gmail.com>
+---
+ drivers/input/mouse/alps.c | 67 ++++++++++++++++++++++++++++++++++++++++++++--
+ drivers/input/mouse/alps.h | 1 +
+ 2 files changed, 66 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
+index 9c97531..0238e0e 100644
+--- a/drivers/input/mouse/alps.c
++++ b/drivers/input/mouse/alps.c
+@@ -490,6 +490,29 @@ static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p)
+ f->y_map |= (p[5] & 0x20) << 6;
+ }
+
++static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p)
++{
++ f->first_mp = !!(p[0] & 0x02);
++ f->is_mp = !!(p[0] & 0x20);
++
++ f->fingers = ((p[0] & 0x6) >> 1 |
++ (p[0] & 0x10) >> 2);
++ f->x_map = ((p[2] & 0x60) >> 5) |
++ ((p[4] & 0x7f) << 2) |
++ ((p[5] & 0x7f) << 9) |
++ ((p[3] & 0x07) << 16) |
++ ((p[3] & 0x70) << 15) |
++ ((p[0] & 0x01) << 22);
++ f->y_map = (p[1] & 0x7f) |
++ ((p[2] & 0x1f) << 7);
++
++ f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
++ f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
++ f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
++
++ alps_decode_buttons_v3(f, p);
++}
++
+ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
+ {
+ struct alps_data *priv = psmouse->private;
+@@ -874,7 +897,8 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
+ }
+
+ /* Bytes 2 - pktsize should have 0 in the highest bit */
+- if (psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
++ if (priv->proto_version != ALPS_PROTO_V5 &&
++ psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
+ (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
+ psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
+ psmouse->pktcnt - 1,
+@@ -1003,7 +1027,8 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
+ return -1;
+ }
+
+- if (param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) {
++ if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
++ param[0] != 0x73) {
+ psmouse_dbg(psmouse,
+ "unknown response while entering command mode\n");
+ return -1;
+@@ -1495,6 +1520,23 @@ error:
+ return -1;
+ }
+
++static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
++{
++ struct ps2dev *ps2dev = &psmouse->ps2dev;
++ unsigned char param[2];
++
++ /* This is dolphin "v1" as empirically defined by florin9doi */
++ param[0] = 0x64;
++ param[1] = 0x28;
++
++ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
++ ps2_command(ps2dev, &param[0], PSMOUSE_CMD_SETRATE) ||
++ ps2_command(ps2dev, &param[1], PSMOUSE_CMD_SETRATE))
++ return -1;
++
++ return 0;
++}
++
+ static void alps_set_defaults(struct alps_data *priv)
+ {
+ priv->byte0 = 0x8f;
+@@ -1528,6 +1570,21 @@ static void alps_set_defaults(struct alps_data *priv)
+ priv->nibble_commands = alps_v4_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_DISABLE;
+ break;
++ case ALPS_PROTO_V5:
++ priv->hw_init = alps_hw_init_dolphin_v1;
++ priv->process_packet = alps_process_packet_v3;
++ priv->decode_fields = alps_decode_dolphin;
++ priv->set_abs_params = alps_set_abs_params_mt;
++ priv->nibble_commands = alps_v3_nibble_commands;
++ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
++ priv->byte0 = 0xc8;
++ priv->mask0 = 0xc8;
++ priv->flags = 0;
++ priv->x_max = 1360;
++ priv->y_max = 660;
++ priv->x_bits = 23;
++ priv->y_bits = 12;
++ break;
+ }
+ }
+
+@@ -1588,6 +1645,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
+
+ if (alps_match_table(psmouse, priv, e7, ec) == 0) {
+ return 0;
++ } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
++ ec[0] == 0x73 && ec[1] == 0x01) {
++ priv->proto_version = ALPS_PROTO_V5;
++ alps_set_defaults(priv);
++
++ return 0;
+ } else if (ec[0] == 0x88 && ec[1] == 0x08) {
+ priv->proto_version = ALPS_PROTO_V3;
+ alps_set_defaults(priv);
+diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
+index 9704805..eee5985 100644
+--- a/drivers/input/mouse/alps.h
++++ b/drivers/input/mouse/alps.h
+@@ -16,6 +16,7 @@
+ #define ALPS_PROTO_V2 2
+ #define ALPS_PROTO_V3 3
+ #define ALPS_PROTO_V4 4
++#define ALPS_PROTO_V5 5
+
+ /**
+ * struct alps_model_info - touchpad ID table
+--
+1.8.1.2
+
diff --git a/freed-ora/current/master/config-generic b/freed-ora/current/master/config-generic
index fc45258e4..96fe207a0 100644
--- a/freed-ora/current/master/config-generic
+++ b/freed-ora/current/master/config-generic
@@ -3953,7 +3953,8 @@ CONFIG_SECURITY_SELINUX_AVC_STATS=y
# CONFIG_SECURITY_YAMA is not set
CONFIG_AUDIT=y
CONFIG_AUDITSYSCALL=y
-# CONFIG_AUDIT_LOGINUID_IMMUTABLE is not set
+# http://lists.fedoraproject.org/pipermail/kernel/2013-February/004125.html
+CONFIG_AUDIT_LOGINUID_IMMUTABLE=y
#
# Cryptographic options
@@ -4520,7 +4521,7 @@ CONFIG_STRIP_ASM_SYMS=y
# CONFIG_RCU_FANOUT_EXACT is not set
# FIXME: Revisit FAST_NO_HZ after it's fixed
-# CONFIG_RCU_FAST_NO_HZ is not setA
+# CONFIG_RCU_FAST_NO_HZ is not set
# CONFIG_RCU_NOCB_CPU is not set
CONFIG_RCU_CPU_STALL_TIMEOUT=60
# CONFIG_RCU_TORTURE_TEST is not set
@@ -4643,6 +4644,8 @@ CONFIG_IOMMU_SUPPORT=y
# CONFIG_PM_DEVFREQ is not set
# CONFIG_MODULE_SIG is not set
+# CONFIG_SYSTEM_TRUSTED_KEYRING is not set
+# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set
# CONFIG_MODULE_VERIFY_ELF is not set
# CONFIG_CRYPTO_KEY_TYPE is not set
# CONFIG_PGP_LIBRARY is not set
diff --git a/freed-ora/current/master/config-x86-generic b/freed-ora/current/master/config-x86-generic
index e8335a2f0..45552bd23 100644
--- a/freed-ora/current/master/config-x86-generic
+++ b/freed-ora/current/master/config-x86-generic
@@ -428,9 +428,12 @@ CONFIG_INTEL_MEI=m
# CONFIG_DEBUG_NMI_SELFTEST is not set
CONFIG_MPILIB=y
+CONFIG_PKCS7_MESSAGE_PARSER=y
+CONFIG_PE_FILE_PARSER=y
CONFIG_MODULE_SIG=y
# CONFIG_MODULE_SIG_SHA1 is not set
CONFIG_MODULE_SIG_SHA256=y
# CONFIG_MODULE_SIG_FORCE is not set
-CONFIG_MODULE_SIG_BLACKLIST=y
+CONFIG_SYSTEM_BLACKLIST_KEYRING=y
+
CONFIG_MODULE_SIG_UEFI=y
diff --git a/freed-ora/current/master/devel-pekey-secure-boot-20130219.patch b/freed-ora/current/master/devel-pekey-secure-boot-20130219.patch
new file mode 100644
index 000000000..0c49c5a2e
--- /dev/null
+++ b/freed-ora/current/master/devel-pekey-secure-boot-20130219.patch
@@ -0,0 +1,5861 @@
+From 11e4fd0629497bbf56245e6aa3a776f350e1f340 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 18 Jan 2013 13:53:35 +0000
+Subject: [PATCH 01/46] KEYS: Load *.x509 files into kernel keyring
+
+Load all the files matching the pattern "*.x509" that are to be found in kernel
+base source dir and base build dir into the module signing keyring.
+
+The "extra_certificates" file is then redundant.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ kernel/Makefile | 35 +++++++++++++++++++++++++++++------
+ kernel/modsign_certificate.S | 3 +--
+ 2 files changed, 30 insertions(+), 8 deletions(-)
+
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 6c072b6..bdabd1d 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -134,17 +134,40 @@ $(obj)/timeconst.h: $(src)/timeconst.pl FORCE
+ $(call if_changed,timeconst)
+
+ ifeq ($(CONFIG_MODULE_SIG),y)
++###############################################################################
+ #
+-# Pull the signing certificate and any extra certificates into the kernel
++# Roll all the X.509 certificates that we can find together and pull
++# them into the kernel.
+ #
++###############################################################################
++X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509)
++X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509
++X509_CERTIFICATES := $(sort $(X509_CERTIFICATES-y))
++
++ifeq ($(X509_CERTIFICATES),)
++$(warning *** No X.509 certificates found ***)
++endif
++
++ifneq ($(wildcard $(obj)/.x509.list),)
++ifneq ($(shell cat $(obj)/.x509.list),$(X509_CERTIFICATES))
++$(info X.509 certificate list changed)
++$(shell rm $(obj)/.x509.list)
++endif
++endif
++
++kernel/modsign_certificate.o: $(obj)/x509_certificate_list
+
+-quiet_cmd_touch = TOUCH $@
+- cmd_touch = touch $@
++quiet_cmd_x509certs = CERTS $@
++ cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@
++targets += $(obj)/x509_certificate_list
++$(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
++ $(call if_changed,x509certs)
+
+-extra_certificates:
+- $(call cmd,touch)
++targets += $(obj)/.x509.list
++$(obj)/.x509.list:
++ @echo $(X509_CERTIFICATES) >$@
+
+-kernel/modsign_certificate.o: signing_key.x509 extra_certificates
++clean-files := x509_certificate_list .x509.list
+
+ ###############################################################################
+ #
+diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S
+index 246b4c6..0a60203 100644
+--- a/kernel/modsign_certificate.S
++++ b/kernel/modsign_certificate.S
+@@ -14,6 +14,5 @@
+ .section ".init.data","aw"
+
+ GLOBAL(modsign_certificate_list)
+- .incbin "signing_key.x509"
+- .incbin "extra_certificates"
++ .incbin "kernel/x509_certificate_list"
+ GLOBAL(modsign_certificate_list_end)
+--
+1.8.1.2
+
+
+From 9029c0a6ee6069d1da0c40a10ac7fbc9ab11241d Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 18:39:54 +0000
+Subject: [PATCH 02/46] KEYS: Separate the kernel signature checking keyring
+ from module signing
+
+Separate the kernel signature checking keyring from module signing so that it
+can be used by code other than the module-signing code.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ include/keys/system_keyring.h | 23 ++++++++++
+ init/Kconfig | 13 ++++++
+ kernel/Makefile | 17 ++++---
+ kernel/modsign_certificate.S | 18 --------
+ kernel/modsign_pubkey.c | 104 ------------------------------------------
+ kernel/module-internal.h | 2 -
+ kernel/module_signing.c | 3 +-
+ kernel/system_certificates.S | 18 ++++++++
+ kernel/system_keyring.c | 101 ++++++++++++++++++++++++++++++++++++++++
+ 9 files changed, 168 insertions(+), 131 deletions(-)
+ create mode 100644 include/keys/system_keyring.h
+ delete mode 100644 kernel/modsign_certificate.S
+ delete mode 100644 kernel/modsign_pubkey.c
+ create mode 100644 kernel/system_certificates.S
+ create mode 100644 kernel/system_keyring.c
+
+diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
+new file mode 100644
+index 0000000..8dabc39
+--- /dev/null
++++ b/include/keys/system_keyring.h
+@@ -0,0 +1,23 @@
++/* System keyring containing trusted public keys.
++ *
++ * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#ifndef _KEYS_SYSTEM_KEYRING_H
++#define _KEYS_SYSTEM_KEYRING_H
++
++#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
++
++#include <linux/key.h>
++
++extern struct key *system_trusted_keyring;
++
++#endif
++
++#endif /* _KEYS_SYSTEM_KEYRING_H */
+diff --git a/init/Kconfig b/init/Kconfig
+index be8b7f5..e05877b 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1568,6 +1568,18 @@ config BASE_SMALL
+ default 0 if BASE_FULL
+ default 1 if !BASE_FULL
+
++config SYSTEM_TRUSTED_KEYRING
++ bool "Provide system-wide ring of trusted keys"
++ depends on KEYS
++ help
++ Provide a system keyring to which trusted keys can be added. Keys in
++ the keyring are considered to be trusted. Keys may be added at will
++ by the kernel from compiled-in data and from hardware key stores, but
++ userspace may only add extra keys if those keys can be verified by
++ keys already in the keyring.
++
++ Keys in this keyring are used by module signature checking.
++
+ menuconfig MODULES
+ bool "Enable loadable module support"
+ help
+@@ -1640,6 +1652,7 @@ config MODULE_SRCVERSION_ALL
+ config MODULE_SIG
+ bool "Module signature verification"
+ depends on MODULES
++ select SYSTEM_TRUSTED_KEYRING
+ select KEYS
+ select CRYPTO
+ select ASYMMETRIC_KEY_TYPE
+diff --git a/kernel/Makefile b/kernel/Makefile
+index bdabd1d..0ca8c0a 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -53,8 +53,9 @@ obj-$(CONFIG_SMP) += spinlock.o
+ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
+ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
+ obj-$(CONFIG_UID16) += uid16.o
++obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
+ obj-$(CONFIG_MODULES) += module.o
+-obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o
++obj-$(CONFIG_MODULE_SIG) += module_signing.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_KEXEC) += kexec.o
+@@ -133,13 +134,14 @@ targets += timeconst.h
+ $(obj)/timeconst.h: $(src)/timeconst.pl FORCE
+ $(call if_changed,timeconst)
+
+-ifeq ($(CONFIG_MODULE_SIG),y)
+ ###############################################################################
+ #
+-# Roll all the X.509 certificates that we can find together and pull
+-# them into the kernel.
++# Roll all the X.509 certificates that we can find together and pull them into
++# the kernel so that they get loaded into the system trusted keyring during
++# boot.
+ #
+ ###############################################################################
++ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
+ X509_CERTIFICATES-y := $(wildcard *.x509) $(wildcard $(srctree)/*.x509)
+ X509_CERTIFICATES-$(CONFIG_MODULE_SIG) += signing_key.x509
+ X509_CERTIFICATES := $(sort $(X509_CERTIFICATES-y))
+@@ -155,10 +157,11 @@ $(shell rm $(obj)/.x509.list)
+ endif
+ endif
+
+-kernel/modsign_certificate.o: $(obj)/x509_certificate_list
++kernel/system_certificates.o: $(obj)/x509_certificate_list
+
+ quiet_cmd_x509certs = CERTS $@
+- cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@
++ cmd_x509certs = cat $(X509_CERTIFICATES) /dev/null >$@ $(foreach X509,$(X509_CERTIFICATES),; echo " - Including cert $(X509)")
++
+ targets += $(obj)/x509_certificate_list
+ $(obj)/x509_certificate_list: $(X509_CERTIFICATES) $(obj)/.x509.list
+ $(call if_changed,x509certs)
+@@ -168,7 +171,9 @@ $(obj)/.x509.list:
+ @echo $(X509_CERTIFICATES) >$@
+
+ clean-files := x509_certificate_list .x509.list
++endif
+
++ifeq ($(CONFIG_MODULE_SIG),y)
+ ###############################################################################
+ #
+ # If module signing is requested, say by allyesconfig, but a key has not been
+diff --git a/kernel/modsign_certificate.S b/kernel/modsign_certificate.S
+deleted file mode 100644
+index 0a60203..0000000
+--- a/kernel/modsign_certificate.S
++++ /dev/null
+@@ -1,18 +0,0 @@
+-/* SYMBOL_PREFIX defined on commandline from CONFIG_SYMBOL_PREFIX */
+-#ifndef SYMBOL_PREFIX
+-#define ASM_SYMBOL(sym) sym
+-#else
+-#define PASTE2(x,y) x##y
+-#define PASTE(x,y) PASTE2(x,y)
+-#define ASM_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym)
+-#endif
+-
+-#define GLOBAL(name) \
+- .globl ASM_SYMBOL(name); \
+- ASM_SYMBOL(name):
+-
+- .section ".init.data","aw"
+-
+-GLOBAL(modsign_certificate_list)
+- .incbin "kernel/x509_certificate_list"
+-GLOBAL(modsign_certificate_list_end)
+diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
+deleted file mode 100644
+index 2b6e699..0000000
+--- a/kernel/modsign_pubkey.c
++++ /dev/null
+@@ -1,104 +0,0 @@
+-/* Public keys for module signature verification
+- *
+- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+- * Written by David Howells (dhowells@redhat.com)
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public Licence
+- * as published by the Free Software Foundation; either version
+- * 2 of the Licence, or (at your option) any later version.
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/sched.h>
+-#include <linux/cred.h>
+-#include <linux/err.h>
+-#include <keys/asymmetric-type.h>
+-#include "module-internal.h"
+-
+-struct key *modsign_keyring;
+-
+-extern __initdata const u8 modsign_certificate_list[];
+-extern __initdata const u8 modsign_certificate_list_end[];
+-
+-/*
+- * We need to make sure ccache doesn't cache the .o file as it doesn't notice
+- * if modsign.pub changes.
+- */
+-static __initdata const char annoy_ccache[] = __TIME__ "foo";
+-
+-/*
+- * Load the compiled-in keys
+- */
+-static __init int module_verify_init(void)
+-{
+- pr_notice("Initialise module verification\n");
+-
+- modsign_keyring = keyring_alloc(".module_sign",
+- KUIDT_INIT(0), KGIDT_INIT(0),
+- current_cred(),
+- ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+- KEY_USR_VIEW | KEY_USR_READ),
+- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+- if (IS_ERR(modsign_keyring))
+- panic("Can't allocate module signing keyring\n");
+-
+- return 0;
+-}
+-
+-/*
+- * Must be initialised before we try and load the keys into the keyring.
+- */
+-device_initcall(module_verify_init);
+-
+-/*
+- * Load the compiled-in keys
+- */
+-static __init int load_module_signing_keys(void)
+-{
+- key_ref_t key;
+- const u8 *p, *end;
+- size_t plen;
+-
+- pr_notice("Loading module verification certificates\n");
+-
+- end = modsign_certificate_list_end;
+- p = modsign_certificate_list;
+- while (p < end) {
+- /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
+- * than 256 bytes in size.
+- */
+- if (end - p < 4)
+- goto dodgy_cert;
+- if (p[0] != 0x30 &&
+- p[1] != 0x82)
+- goto dodgy_cert;
+- plen = (p[2] << 8) | p[3];
+- plen += 4;
+- if (plen > end - p)
+- goto dodgy_cert;
+-
+- key = key_create_or_update(make_key_ref(modsign_keyring, 1),
+- "asymmetric",
+- NULL,
+- p,
+- plen,
+- (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+- KEY_USR_VIEW,
+- KEY_ALLOC_NOT_IN_QUOTA);
+- if (IS_ERR(key))
+- pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
+- PTR_ERR(key));
+- else
+- pr_notice("MODSIGN: Loaded cert '%s'\n",
+- key_ref_to_ptr(key)->description);
+- p += plen;
+- }
+-
+- return 0;
+-
+-dodgy_cert:
+- pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n");
+- return 0;
+-}
+-late_initcall(load_module_signing_keys);
+diff --git a/kernel/module-internal.h b/kernel/module-internal.h
+index 24f9247..915e123 100644
+--- a/kernel/module-internal.h
++++ b/kernel/module-internal.h
+@@ -9,6 +9,4 @@
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+-extern struct key *modsign_keyring;
+-
+ extern int mod_verify_sig(const void *mod, unsigned long *_modlen);
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index f2970bd..0034e36 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -14,6 +14,7 @@
+ #include <crypto/public_key.h>
+ #include <crypto/hash.h>
+ #include <keys/asymmetric-type.h>
++#include <keys/system_keyring.h>
+ #include "module-internal.h"
+
+ /*
+@@ -157,7 +158,7 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
+
+ pr_debug("Look up: \"%s\"\n", id);
+
+- key = keyring_search(make_key_ref(modsign_keyring, 1),
++ key = keyring_search(make_key_ref(system_trusted_keyring, 1),
+ &key_type_asymmetric, id);
+ if (IS_ERR(key))
+ pr_warn("Request for unknown module key '%s' err %ld\n",
+diff --git a/kernel/system_certificates.S b/kernel/system_certificates.S
+new file mode 100644
+index 0000000..86240df
+--- /dev/null
++++ b/kernel/system_certificates.S
+@@ -0,0 +1,18 @@
++/* SYMBOL_PREFIX defined on commandline from CONFIG_SYMBOL_PREFIX */
++#ifndef SYMBOL_PREFIX
++#define ASM_SYMBOL(sym) sym
++#else
++#define PASTE2(x,y) x##y
++#define PASTE(x,y) PASTE2(x,y)
++#define ASM_SYMBOL(sym) PASTE(SYMBOL_PREFIX, sym)
++#endif
++
++#define GLOBAL(name) \
++ .globl ASM_SYMBOL(name); \
++ ASM_SYMBOL(name):
++
++ .section ".init.data","aw"
++
++GLOBAL(system_certificate_list)
++ .incbin "kernel/x509_certificate_list"
++GLOBAL(system_certificate_list_end)
+diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
+new file mode 100644
+index 0000000..a3ca76f
+--- /dev/null
++++ b/kernel/system_keyring.c
+@@ -0,0 +1,101 @@
++/* System trusted keyring for trusted public keys
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <linux/export.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/cred.h>
++#include <linux/err.h>
++#include <keys/asymmetric-type.h>
++#include <keys/system_keyring.h>
++#include "module-internal.h"
++
++struct key *system_trusted_keyring;
++EXPORT_SYMBOL_GPL(system_trusted_keyring);
++
++extern __initdata const u8 system_certificate_list[];
++extern __initdata const u8 system_certificate_list_end[];
++
++/*
++ * Load the compiled-in keys
++ */
++static __init int system_trusted_keyring_init(void)
++{
++ pr_notice("Initialise system trusted keyring\n");
++
++ system_trusted_keyring =
++ keyring_alloc(".system_keyring",
++ KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
++ ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
++ KEY_USR_VIEW | KEY_USR_READ),
++ KEY_ALLOC_NOT_IN_QUOTA, NULL);
++ if (IS_ERR(system_trusted_keyring))
++ panic("Can't allocate system trusted keyring\n");
++
++ return 0;
++}
++
++/*
++ * Must be initialised before we try and load the keys into the keyring.
++ */
++device_initcall(system_trusted_keyring_init);
++
++/*
++ * Load the compiled-in list of X.509 certificates.
++ */
++static __init int load_system_certificate_list(void)
++{
++ key_ref_t key;
++ const u8 *p, *end;
++ size_t plen;
++
++ pr_notice("Loading compiled-in X.509 certificates\n");
++
++ end = system_certificate_list_end;
++ p = system_certificate_list;
++ while (p < end) {
++ /* Each cert begins with an ASN.1 SEQUENCE tag and must be more
++ * than 256 bytes in size.
++ */
++ if (end - p < 4)
++ goto dodgy_cert;
++ if (p[0] != 0x30 &&
++ p[1] != 0x82)
++ goto dodgy_cert;
++ plen = (p[2] << 8) | p[3];
++ plen += 4;
++ if (plen > end - p)
++ goto dodgy_cert;
++
++ key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
++ "asymmetric",
++ NULL,
++ p,
++ plen,
++ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
++ KEY_USR_VIEW,
++ KEY_ALLOC_NOT_IN_QUOTA);
++ if (IS_ERR(key))
++ pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
++ PTR_ERR(key));
++ else
++ pr_notice("Loaded X.509 cert '%s'\n",
++ key_ref_to_ptr(key)->description);
++ p += plen;
++ }
++
++ return 0;
++
++dodgy_cert:
++ pr_err("Problem parsing in-kernel X.509 certificate list\n");
++ return 0;
++}
++late_initcall(load_system_certificate_list);
+--
+1.8.1.2
+
+
+From ff91a380ea23be02cbb7de1af30845c6ec275d41 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 17 Jan 2013 16:25:00 +0000
+Subject: [PATCH 03/46] KEYS: Add a 'trusted' flag and a 'trusted only' flag
+
+Add KEY_FLAG_TRUSTED to indicate that a key either comes from a trusted source
+or had a cryptographic signature chain that led back to a trusted key the
+kernel already possessed.
+
+Add KEY_FLAGS_TRUSTED_ONLY to indicate that a keyring will only accept links to
+keys marked with KEY_FLAGS_TRUSTED.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ include/linux/key-type.h | 1 +
+ include/linux/key.h | 3 +++
+ kernel/system_keyring.c | 4 +++-
+ security/keys/key.c | 8 ++++++++
+ security/keys/keyring.c | 4 ++++
+ 5 files changed, 19 insertions(+), 1 deletion(-)
+
+diff --git a/include/linux/key-type.h b/include/linux/key-type.h
+index 518a53a..f942b2d 100644
+--- a/include/linux/key-type.h
++++ b/include/linux/key-type.h
+@@ -45,6 +45,7 @@ struct key_preparsed_payload {
+ const void *data; /* Raw data */
+ size_t datalen; /* Raw datalen */
+ size_t quotalen; /* Quota length for proposed payload */
++ bool trusted; /* True if key is trusted */
+ };
+
+ typedef int (*request_key_actor_t)(struct key_construction *key,
+diff --git a/include/linux/key.h b/include/linux/key.h
+index 4dfde11..0b32a09 100644
+--- a/include/linux/key.h
++++ b/include/linux/key.h
+@@ -162,6 +162,8 @@ struct key {
+ #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */
+ #define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */
+ #define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */
++#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */
++#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
+
+ /* the description string
+ * - this is used to match a key against search criteria
+@@ -203,6 +205,7 @@ extern struct key *key_alloc(struct key_type *type,
+ #define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */
+ #define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
+ #define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
++#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */
+
+ extern void key_revoke(struct key *key);
+ extern void key_invalidate(struct key *key);
+diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
+index a3ca76f..dae8778 100644
+--- a/kernel/system_keyring.c
++++ b/kernel/system_keyring.c
+@@ -40,6 +40,7 @@ static __init int system_trusted_keyring_init(void)
+ if (IS_ERR(system_trusted_keyring))
+ panic("Can't allocate system trusted keyring\n");
+
++ set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
+ return 0;
+ }
+
+@@ -82,7 +83,8 @@ static __init int load_system_certificate_list(void)
+ plen,
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW,
+- KEY_ALLOC_NOT_IN_QUOTA);
++ KEY_ALLOC_NOT_IN_QUOTA |
++ KEY_ALLOC_TRUSTED);
+ if (IS_ERR(key))
+ pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
+ PTR_ERR(key));
+diff --git a/security/keys/key.c b/security/keys/key.c
+index 8fb7c7b..f3de9e4 100644
+--- a/security/keys/key.c
++++ b/security/keys/key.c
+@@ -299,6 +299,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
+
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
+ key->flags |= 1 << KEY_FLAG_IN_QUOTA;
++ if (flags & KEY_ALLOC_TRUSTED)
++ key->flags |= 1 << KEY_FLAG_TRUSTED;
+
+ memset(&key->type_data, 0, sizeof(key->type_data));
+
+@@ -813,6 +815,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
+ prep.data = payload;
+ prep.datalen = plen;
+ prep.quotalen = ktype->def_datalen;
++ prep.trusted = flags & KEY_ALLOC_TRUSTED;
+ if (ktype->preparse) {
+ ret = ktype->preparse(&prep);
+ if (ret < 0) {
+@@ -826,6 +829,11 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
+ goto error_free_prep;
+ }
+
++ key_ref = ERR_PTR(-EPERM);
++ if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags))
++ goto error_free_prep;
++ flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0;
++
+ ret = __key_link_begin(keyring, ktype, description, &prealloc);
+ if (ret < 0) {
+ key_ref = ERR_PTR(ret);
+diff --git a/security/keys/keyring.c b/security/keys/keyring.c
+index 6ece7f2..f18d7ff 100644
+--- a/security/keys/keyring.c
++++ b/security/keys/keyring.c
+@@ -1006,6 +1006,10 @@ int key_link(struct key *keyring, struct key *key)
+ key_check(keyring);
+ key_check(key);
+
++ if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) &&
++ !test_bit(KEY_FLAG_TRUSTED, &key->flags))
++ return -EPERM;
++
+ ret = __key_link_begin(keyring, key->type, key->description, &prealloc);
+ if (ret == 0) {
+ ret = __key_link_check_live_key(keyring, key);
+--
+1.8.1.2
+
+
+From 47fb497e684ae5efa3c5573247917a528bdf8cee Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:32 +0000
+Subject: [PATCH 04/46] KEYS: Rename public key parameter name arrays
+
+Rename the arrays of public key parameters (public key algorithm names, hash
+algorithm names and ID type names) so that the array name ends in "_name".
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/public_key.c | 14 +++++++-------
+ crypto/asymmetric_keys/x509_public_key.c | 8 ++++----
+ include/crypto/public_key.h | 6 +++---
+ kernel/module_signing.c | 4 ++--
+ 4 files changed, 16 insertions(+), 16 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
+index cb2e291..b313df1 100644
+--- a/crypto/asymmetric_keys/public_key.c
++++ b/crypto/asymmetric_keys/public_key.c
+@@ -22,13 +22,13 @@
+
+ MODULE_LICENSE("GPL");
+
+-const char *const pkey_algo[PKEY_ALGO__LAST] = {
++const char *const pkey_algo_name[PKEY_ALGO__LAST] = {
+ [PKEY_ALGO_DSA] = "DSA",
+ [PKEY_ALGO_RSA] = "RSA",
+ };
+-EXPORT_SYMBOL_GPL(pkey_algo);
++EXPORT_SYMBOL_GPL(pkey_algo_name);
+
+-const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
++const char *const pkey_hash_algo_name[PKEY_HASH__LAST] = {
+ [PKEY_HASH_MD4] = "md4",
+ [PKEY_HASH_MD5] = "md5",
+ [PKEY_HASH_SHA1] = "sha1",
+@@ -38,13 +38,13 @@ const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
+ [PKEY_HASH_SHA512] = "sha512",
+ [PKEY_HASH_SHA224] = "sha224",
+ };
+-EXPORT_SYMBOL_GPL(pkey_hash_algo);
++EXPORT_SYMBOL_GPL(pkey_hash_algo_name);
+
+-const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
++const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
+ [PKEY_ID_PGP] = "PGP",
+ [PKEY_ID_X509] = "X509",
+ };
+-EXPORT_SYMBOL_GPL(pkey_id_type);
++EXPORT_SYMBOL_GPL(pkey_id_type_name);
+
+ /*
+ * Provide a part of a description of the key for /proc/keys.
+@@ -56,7 +56,7 @@ static void public_key_describe(const struct key *asymmetric_key,
+
+ if (key)
+ seq_printf(m, "%s.%s",
+- pkey_id_type[key->id_type], key->algo->name);
++ pkey_id_type_name[key->id_type], key->algo->name);
+ }
+
+ /*
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index 06007f0..afbbc36 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -49,7 +49,7 @@ static int x509_check_signature(const struct public_key *pub,
+ /* Allocate the hashing algorithm we're going to need and find out how
+ * big the hash operational data will be.
+ */
+- tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_hash_algo], 0, 0);
++ tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig_hash_algo], 0, 0);
+ if (IS_ERR(tfm))
+ return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+
+@@ -117,7 +117,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+
+ pr_devel("Cert Issuer: %s\n", cert->issuer);
+ pr_devel("Cert Subject: %s\n", cert->subject);
+- pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
++ pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pkey_algo]);
+ pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
+ cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
+ cert->valid_from.tm_mday, cert->valid_from.tm_hour,
+@@ -127,8 +127,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ cert->valid_to.tm_mday, cert->valid_to.tm_hour,
+ cert->valid_to.tm_min, cert->valid_to.tm_sec);
+ pr_devel("Cert Signature: %s + %s\n",
+- pkey_algo[cert->sig_pkey_algo],
+- pkey_hash_algo[cert->sig_hash_algo]);
++ pkey_algo_name[cert->sig_pkey_algo],
++ pkey_hash_algo_name[cert->sig_hash_algo]);
+
+ if (!cert->fingerprint || !cert->authority) {
+ pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
+diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
+index f5b0224..619d570 100644
+--- a/include/crypto/public_key.h
++++ b/include/crypto/public_key.h
+@@ -22,7 +22,7 @@ enum pkey_algo {
+ PKEY_ALGO__LAST
+ };
+
+-extern const char *const pkey_algo[PKEY_ALGO__LAST];
++extern const char *const pkey_algo_name[PKEY_ALGO__LAST];
+
+ enum pkey_hash_algo {
+ PKEY_HASH_MD4,
+@@ -36,7 +36,7 @@ enum pkey_hash_algo {
+ PKEY_HASH__LAST
+ };
+
+-extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
++extern const char *const pkey_hash_algo_name[PKEY_HASH__LAST];
+
+ enum pkey_id_type {
+ PKEY_ID_PGP, /* OpenPGP generated key ID */
+@@ -44,7 +44,7 @@ enum pkey_id_type {
+ PKEY_ID_TYPE__LAST
+ };
+
+-extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST];
++extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
+
+ /*
+ * Cryptographic data for the public-key subtype of the asymmetric key type.
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index 0034e36..0b6b870 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -55,7 +55,7 @@ static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
+ /* Allocate the hashing algorithm we're going to need and find out how
+ * big the hash operational data will be.
+ */
+- tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0);
++ tfm = crypto_alloc_shash(pkey_hash_algo_name[hash], 0, 0);
+ if (IS_ERR(tfm))
+ return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
+
+@@ -218,7 +218,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
+ return -ENOPKG;
+
+ if (ms.hash >= PKEY_HASH__LAST ||
+- !pkey_hash_algo[ms.hash])
++ !pkey_hash_algo_name[ms.hash])
+ return -ENOPKG;
+
+ key = request_asymmetric_key(sig, ms.signer_len,
+--
+1.8.1.2
+
+
+From f8383dd2291f8bceb9bfb185c162c537c8a0befb Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:33 +0000
+Subject: [PATCH 05/46] KEYS: Move the algorithm pointer array from x509 to
+ public_key.c
+
+Move the public-key algorithm pointer array from x509_public_key.c to
+public_key.c as it isn't X.509 specific.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/public_key.c | 8 ++++++++
+ crypto/asymmetric_keys/x509_public_key.c | 11 +----------
+ include/crypto/public_key.h | 1 +
+ 3 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
+index b313df1..796ce08 100644
+--- a/crypto/asymmetric_keys/public_key.c
++++ b/crypto/asymmetric_keys/public_key.c
+@@ -28,6 +28,14 @@ const char *const pkey_algo_name[PKEY_ALGO__LAST] = {
+ };
+ EXPORT_SYMBOL_GPL(pkey_algo_name);
+
++const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST] = {
++#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
++ defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
++ [PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
++#endif
++};
++EXPORT_SYMBOL_GPL(pkey_algo);
++
+ const char *const pkey_hash_algo_name[PKEY_HASH__LAST] = {
+ [PKEY_HASH_MD4] = "md4",
+ [PKEY_HASH_MD5] = "md5",
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index afbbc36..fe38628 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -23,15 +23,6 @@
+ #include "public_key.h"
+ #include "x509_parser.h"
+
+-static const
+-struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = {
+- [PKEY_ALGO_DSA] = NULL,
+-#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
+- defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
+- [PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
+-#endif
+-};
+-
+ /*
+ * Check the signature on a certificate using the provided public key
+ */
+@@ -174,7 +165,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ goto error_free_cert;
+ }
+
+- cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
++ cert->pub->algo = pkey_algo[cert->pkey_algo];
+ cert->pub->id_type = PKEY_ID_X509;
+
+ /* Check the signature on the key */
+diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
+index 619d570..46bde25 100644
+--- a/include/crypto/public_key.h
++++ b/include/crypto/public_key.h
+@@ -23,6 +23,7 @@ enum pkey_algo {
+ };
+
+ extern const char *const pkey_algo_name[PKEY_ALGO__LAST];
++extern const struct public_key_algorithm *pkey_algo[PKEY_ALGO__LAST];
+
+ enum pkey_hash_algo {
+ PKEY_HASH_MD4,
+--
+1.8.1.2
+
+
+From 34e16d2c23a9ba6c54447ce81c52fe5807d26dd2 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:33 +0000
+Subject: [PATCH 06/46] KEYS: Store public key algo ID in public_key struct
+
+Store public key algo ID in public_key struct for reference purposes. This
+allows it to be removed from the x509_certificate struct and used to find a
+default in public_key_verify_signature().
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/x509_cert_parser.c | 5 +++--
+ crypto/asymmetric_keys/x509_parser.h | 1 -
+ crypto/asymmetric_keys/x509_public_key.c | 4 ++--
+ include/crypto/public_key.h | 1 +
+ 4 files changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
+index 7fabc4c..a583930 100644
+--- a/crypto/asymmetric_keys/x509_cert_parser.c
++++ b/crypto/asymmetric_keys/x509_cert_parser.c
+@@ -343,8 +343,9 @@ int x509_extract_key_data(void *context, size_t hdrlen,
+ if (ctx->last_oid != OID_rsaEncryption)
+ return -ENOPKG;
+
+- /* There seems to be an extraneous 0 byte on the front of the data */
+- ctx->cert->pkey_algo = PKEY_ALGO_RSA;
++ ctx->cert->pub->pkey_algo = PKEY_ALGO_RSA;
++
++ /* Discard the BIT STRING metadata */
+ ctx->key = value + 1;
+ ctx->key_size = vlen - 1;
+ return 0;
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+index f86dc5f..e583ad0 100644
+--- a/crypto/asymmetric_keys/x509_parser.h
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -20,7 +20,6 @@ struct x509_certificate {
+ char *authority; /* Authority key fingerprint as hex */
+ struct tm valid_from;
+ struct tm valid_to;
+- enum pkey_algo pkey_algo : 8; /* Public key algorithm */
+ enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
+ enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
+ const void *tbs; /* Signed data */
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index fe38628..fac574c 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -108,7 +108,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+
+ pr_devel("Cert Issuer: %s\n", cert->issuer);
+ pr_devel("Cert Subject: %s\n", cert->subject);
+- pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pkey_algo]);
++ pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
+ pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
+ cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
+ cert->valid_from.tm_mday, cert->valid_from.tm_hour,
+@@ -165,7 +165,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ goto error_free_cert;
+ }
+
+- cert->pub->algo = pkey_algo[cert->pkey_algo];
++ cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
+ cert->pub->id_type = PKEY_ID_X509;
+
+ /* Check the signature on the key */
+diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
+index 46bde25..05778df 100644
+--- a/include/crypto/public_key.h
++++ b/include/crypto/public_key.h
+@@ -60,6 +60,7 @@ struct public_key {
+ #define PKEY_CAN_DECRYPT 0x02
+ #define PKEY_CAN_SIGN 0x04
+ #define PKEY_CAN_VERIFY 0x08
++ enum pkey_algo pkey_algo : 8;
+ enum pkey_id_type id_type : 8;
+ union {
+ MPI mpi[5];
+--
+1.8.1.2
+
+
+From d6dd79d03285dc9b32e5ab54a33853881dde01d8 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:34 +0000
+Subject: [PATCH 07/46] KEYS: Split public_key_verify_signature() and make
+ available
+
+Modify public_key_verify_signature() so that it now takes a public_key struct
+rather than a key struct and supply a wrapper that takes a key struct. The
+wrapper is then used by the asymmetric key subtype and the modified function is
+used by X.509 self-signature checking and can be used by PKCS#7 also.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/public_key.c | 40 +++++++++++++++++++++++++-------
+ crypto/asymmetric_keys/public_key.h | 6 +++++
+ crypto/asymmetric_keys/x509_public_key.c | 2 +-
+ 3 files changed, 39 insertions(+), 9 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
+index 796ce08..49ac8d8 100644
+--- a/crypto/asymmetric_keys/public_key.c
++++ b/crypto/asymmetric_keys/public_key.c
+@@ -86,21 +86,45 @@ EXPORT_SYMBOL_GPL(public_key_destroy);
+ /*
+ * Verify a signature using a public key.
+ */
+-static int public_key_verify_signature(const struct key *key,
+- const struct public_key_signature *sig)
++int public_key_verify_signature(const struct public_key *pk,
++ const struct public_key_signature *sig)
+ {
+- const struct public_key *pk = key->payload.data;
++ const struct public_key_algorithm *algo;
++
++ BUG_ON(!pk);
++ BUG_ON(!pk->mpi[0]);
++ BUG_ON(!pk->mpi[1]);
++ BUG_ON(!sig);
++ BUG_ON(!sig->digest);
++ BUG_ON(!sig->mpi[0]);
++
++ algo = pk->algo;
++ if (!algo) {
++ if (pk->pkey_algo >= PKEY_ALGO__LAST)
++ return -ENOPKG;
++ algo = pkey_algo[pk->pkey_algo];
++ if (!algo)
++ return -ENOPKG;
++ }
+
+- if (!pk->algo->verify_signature)
++ if (!algo->verify_signature)
+ return -ENOTSUPP;
+
+- if (sig->nr_mpi != pk->algo->n_sig_mpi) {
++ if (sig->nr_mpi != algo->n_sig_mpi) {
+ pr_debug("Signature has %u MPI not %u\n",
+- sig->nr_mpi, pk->algo->n_sig_mpi);
++ sig->nr_mpi, algo->n_sig_mpi);
+ return -EINVAL;
+ }
+
+- return pk->algo->verify_signature(pk, sig);
++ return algo->verify_signature(pk, sig);
++}
++EXPORT_SYMBOL_GPL(public_key_verify_signature);
++
++static int public_key_verify_signature_2(const struct key *key,
++ const struct public_key_signature *sig)
++{
++ const struct public_key *pk = key->payload.data;
++ return public_key_verify_signature(pk, sig);
+ }
+
+ /*
+@@ -111,6 +135,6 @@ struct asymmetric_key_subtype public_key_subtype = {
+ .name = "public_key",
+ .describe = public_key_describe,
+ .destroy = public_key_destroy,
+- .verify_signature = public_key_verify_signature,
++ .verify_signature = public_key_verify_signature_2,
+ };
+ EXPORT_SYMBOL_GPL(public_key_subtype);
+diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h
+index 5e5e356..5c37a22 100644
+--- a/crypto/asymmetric_keys/public_key.h
++++ b/crypto/asymmetric_keys/public_key.h
+@@ -28,3 +28,9 @@ struct public_key_algorithm {
+ };
+
+ extern const struct public_key_algorithm RSA_public_key_algorithm;
++
++/*
++ * public_key.c
++ */
++extern int public_key_verify_signature(const struct public_key *pk,
++ const struct public_key_signature *sig);
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index fac574c..8cb2f70 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -76,7 +76,7 @@ static int x509_check_signature(const struct public_key *pub,
+ if (ret < 0)
+ goto error_mpi;
+
+- ret = pub->algo->verify_signature(pub, sig);
++ ret = public_key_verify_signature(pub, sig);
+
+ pr_debug("Cert Verification: %d\n", ret);
+
+--
+1.8.1.2
+
+
+From 064a635b699548b2ca23a308db449336a3a4fdf0 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:35 +0000
+Subject: [PATCH 08/46] KEYS: Store public key algo ID in public_key_signature
+ struct
+
+Store public key algorithm ID in public_key_signature struct for reference
+purposes. This allows a public_key_signature struct to be embedded in
+struct x509_certificate and struct pkcs7_message more easily.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ include/crypto/public_key.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
+index 05778df..b34fda4 100644
+--- a/include/crypto/public_key.h
++++ b/include/crypto/public_key.h
+@@ -90,6 +90,7 @@ struct public_key_signature {
+ u8 *digest;
+ u8 digest_size; /* Number of bytes in digest */
+ u8 nr_mpi; /* Occupancy of mpi[] */
++ enum pkey_algo pkey_algo : 8;
+ enum pkey_hash_algo pkey_hash_algo : 8;
+ union {
+ MPI mpi[2];
+--
+1.8.1.2
+
+
+From a0b84a599f5ac6f53227fa74853ba6fa3cb0da23 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:35 +0000
+Subject: [PATCH 09/46] X.509: struct x509_certificate needs struct tm
+ declaring
+
+struct x509_certificate needs struct tm declaring by #inclusion of linux/time.h
+prior to its definition.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/x509_parser.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+index e583ad0..2d01182 100644
+--- a/crypto/asymmetric_keys/x509_parser.h
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -9,6 +9,7 @@
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
++#include <linux/time.h>
+ #include <crypto/public_key.h>
+
+ struct x509_certificate {
+--
+1.8.1.2
+
+
+From e393e194decebbe6b93033318d68b53eeae2d1fb Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:35 +0000
+Subject: [PATCH 10/46] X.509: Add bits needed for PKCS#7
+
+PKCS#7 validation requires access to the serial number and the raw names in an
+X.509 certificate.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/x509.asn1 | 2 +-
+ crypto/asymmetric_keys/x509_cert_parser.c | 17 +++++++++++++++++
+ crypto/asymmetric_keys/x509_parser.h | 10 ++++++++--
+ 3 files changed, 26 insertions(+), 3 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/x509.asn1 b/crypto/asymmetric_keys/x509.asn1
+index bf32b3d..aae0cde 100644
+--- a/crypto/asymmetric_keys/x509.asn1
++++ b/crypto/asymmetric_keys/x509.asn1
+@@ -6,7 +6,7 @@ Certificate ::= SEQUENCE {
+
+ TBSCertificate ::= SEQUENCE {
+ version [ 0 ] Version DEFAULT,
+- serialNumber CertificateSerialNumber,
++ serialNumber CertificateSerialNumber ({ x509_note_serial }),
+ signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
+ issuer Name ({ x509_note_issuer }),
+ validity Validity,
+diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
+index a583930..08bebf1 100644
+--- a/crypto/asymmetric_keys/x509_cert_parser.c
++++ b/crypto/asymmetric_keys/x509_cert_parser.c
+@@ -209,6 +209,19 @@ int x509_note_signature(void *context, size_t hdrlen,
+ }
+
+ /*
++ * Note the certificate serial number
++ */
++int x509_note_serial(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct x509_parse_context *ctx = context;
++ ctx->cert->raw_serial = value;
++ ctx->cert->raw_serial_size = vlen;
++ return 0;
++}
++
++/*
+ * Note some of the name segments from which we'll fabricate a name.
+ */
+ int x509_extract_name_segment(void *context, size_t hdrlen,
+@@ -320,6 +333,8 @@ int x509_note_issuer(void *context, size_t hdrlen,
+ const void *value, size_t vlen)
+ {
+ struct x509_parse_context *ctx = context;
++ ctx->cert->raw_issuer = value;
++ ctx->cert->raw_issuer_size = vlen;
+ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
+ }
+
+@@ -328,6 +343,8 @@ int x509_note_subject(void *context, size_t hdrlen,
+ const void *value, size_t vlen)
+ {
+ struct x509_parse_context *ctx = context;
++ ctx->cert->raw_subject = value;
++ ctx->cert->raw_subject_size = vlen;
+ return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
+ }
+
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+index 2d01182..a6ce46f 100644
+--- a/crypto/asymmetric_keys/x509_parser.h
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -24,9 +24,15 @@ struct x509_certificate {
+ enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
+ enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
+ const void *tbs; /* Signed data */
+- size_t tbs_size; /* Size of signed data */
++ unsigned tbs_size; /* Size of signed data */
++ unsigned sig_size; /* Size of sigature */
+ const void *sig; /* Signature data */
+- size_t sig_size; /* Size of sigature */
++ const void *raw_serial; /* Raw serial number in ASN.1 */
++ unsigned raw_serial_size;
++ unsigned raw_issuer_size;
++ const void *raw_issuer; /* Raw issuer name in ASN.1 */
++ const void *raw_subject; /* Raw subject name in ASN.1 */
++ unsigned raw_subject_size;
+ };
+
+ /*
+--
+1.8.1.2
+
+
+From 85a9279f58f9fc1c1db6e75eb2ff7d88f58139df Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:36 +0000
+Subject: [PATCH 11/46] X.509: Embed public_key_signature struct and create
+ filler function
+
+Embed a public_key_signature struct in struct x509_certificate, eliminating
+now unnecessary fields, and split x509_check_signature() to create a filler
+function for it that attaches a digest of the signed data and an MPI that
+represents the signature data. x509_free_certificate() is then modified to
+deal with these.
+
+Whilst we're at it, export both x509_check_signature() and the new
+x509_get_sig_params().
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/x509_cert_parser.c | 30 +++++------
+ crypto/asymmetric_keys/x509_parser.h | 14 ++++--
+ crypto/asymmetric_keys/x509_public_key.c | 83 +++++++++++++++++--------------
+ 3 files changed, 73 insertions(+), 54 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
+index 08bebf1..931f069 100644
+--- a/crypto/asymmetric_keys/x509_cert_parser.c
++++ b/crypto/asymmetric_keys/x509_cert_parser.c
+@@ -47,6 +47,8 @@ void x509_free_certificate(struct x509_certificate *cert)
+ kfree(cert->subject);
+ kfree(cert->fingerprint);
+ kfree(cert->authority);
++ kfree(cert->sig.digest);
++ mpi_free(cert->sig.rsa.s);
+ kfree(cert);
+ }
+ }
+@@ -152,33 +154,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
+ return -ENOPKG; /* Unsupported combination */
+
+ case OID_md4WithRSAEncryption:
+- ctx->cert->sig_hash_algo = PKEY_HASH_MD5;
+- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_MD5;
++ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ break;
+
+ case OID_sha1WithRSAEncryption:
+- ctx->cert->sig_hash_algo = PKEY_HASH_SHA1;
+- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA1;
++ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ break;
+
+ case OID_sha256WithRSAEncryption:
+- ctx->cert->sig_hash_algo = PKEY_HASH_SHA256;
+- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA256;
++ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ break;
+
+ case OID_sha384WithRSAEncryption:
+- ctx->cert->sig_hash_algo = PKEY_HASH_SHA384;
+- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA384;
++ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ break;
+
+ case OID_sha512WithRSAEncryption:
+- ctx->cert->sig_hash_algo = PKEY_HASH_SHA512;
+- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA512;
++ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ break;
+
+ case OID_sha224WithRSAEncryption:
+- ctx->cert->sig_hash_algo = PKEY_HASH_SHA224;
+- ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
++ ctx->cert->sig.pkey_hash_algo = PKEY_HASH_SHA224;
++ ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+ break;
+ }
+
+@@ -203,8 +205,8 @@ int x509_note_signature(void *context, size_t hdrlen,
+ return -EINVAL;
+ }
+
+- ctx->cert->sig = value;
+- ctx->cert->sig_size = vlen;
++ ctx->cert->raw_sig = value;
++ ctx->cert->raw_sig_size = vlen;
+ return 0;
+ }
+
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+index a6ce46f..6b1d877 100644
+--- a/crypto/asymmetric_keys/x509_parser.h
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -21,18 +21,17 @@ struct x509_certificate {
+ char *authority; /* Authority key fingerprint as hex */
+ struct tm valid_from;
+ struct tm valid_to;
+- enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
+- enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
+ const void *tbs; /* Signed data */
+ unsigned tbs_size; /* Size of signed data */
+- unsigned sig_size; /* Size of sigature */
+- const void *sig; /* Signature data */
++ unsigned raw_sig_size; /* Size of sigature */
++ const void *raw_sig; /* Signature data */
+ const void *raw_serial; /* Raw serial number in ASN.1 */
+ unsigned raw_serial_size;
+ unsigned raw_issuer_size;
+ const void *raw_issuer; /* Raw issuer name in ASN.1 */
+ const void *raw_subject; /* Raw subject name in ASN.1 */
+ unsigned raw_subject_size;
++ struct public_key_signature sig; /* Signature parameters */
+ };
+
+ /*
+@@ -40,3 +39,10 @@ struct x509_certificate {
+ */
+ extern void x509_free_certificate(struct x509_certificate *cert);
+ extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
++
++/*
++ * x509_public_key.c
++ */
++extern int x509_get_sig_params(struct x509_certificate *cert);
++extern int x509_check_signature(const struct public_key *pub,
++ struct x509_certificate *cert);
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index 8cb2f70..b7c81d8 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -24,72 +24,83 @@
+ #include "x509_parser.h"
+
+ /*
+- * Check the signature on a certificate using the provided public key
++ * Set up the signature parameters in an X.509 certificate. This involves
++ * digesting the signed data and extracting the signature.
+ */
+-static int x509_check_signature(const struct public_key *pub,
+- const struct x509_certificate *cert)
++int x509_get_sig_params(struct x509_certificate *cert)
+ {
+- struct public_key_signature *sig;
+ struct crypto_shash *tfm;
+ struct shash_desc *desc;
+ size_t digest_size, desc_size;
++ void *digest;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+-
++
++ if (cert->sig.rsa.s)
++ return 0;
++
++ cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
++ if (!cert->sig.rsa.s)
++ return -ENOMEM;
++ cert->sig.nr_mpi = 1;
++
+ /* Allocate the hashing algorithm we're going to need and find out how
+ * big the hash operational data will be.
+ */
+- tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig_hash_algo], 0, 0);
++ tfm = crypto_alloc_shash(pkey_hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
+ if (IS_ERR(tfm))
+ return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+
+ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+ digest_size = crypto_shash_digestsize(tfm);
+
+- /* We allocate the hash operational data storage on the end of our
+- * context data.
++ /* We allocate the hash operational data storage on the end of the
++ * digest storage space.
+ */
+ ret = -ENOMEM;
+- sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL);
+- if (!sig)
+- goto error_no_sig;
++ digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
++ if (!digest)
++ goto error;
+
+- sig->pkey_hash_algo = cert->sig_hash_algo;
+- sig->digest = (u8 *)sig + sizeof(*sig) + desc_size;
+- sig->digest_size = digest_size;
++ cert->sig.digest = digest;
++ cert->sig.digest_size = digest_size;
+
+- desc = (void *)sig + sizeof(*sig);
+- desc->tfm = tfm;
+- desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++ desc = digest + digest_size;
++ desc->tfm = tfm;
++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ ret = crypto_shash_init(desc);
+ if (ret < 0)
+ goto error;
++ might_sleep();
++ ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
++error:
++ crypto_free_shash(tfm);
++ pr_devel("<==%s() = %d\n", __func__, ret);
++ return ret;
++}
++EXPORT_SYMBOL_GPL(x509_get_sig_params);
+
+- ret = -ENOMEM;
+- sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size);
+- if (!sig->rsa.s)
+- goto error;
++/*
++ * Check the signature on a certificate using the provided public key
++ */
++int x509_check_signature(const struct public_key *pub,
++ struct x509_certificate *cert)
++{
++ int ret;
+
+- ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
+- if (ret < 0)
+- goto error_mpi;
++ pr_devel("==>%s()\n", __func__);
+
+- ret = public_key_verify_signature(pub, sig);
++ ret = x509_get_sig_params(cert);
++ if (ret < 0)
++ return ret;
+
++ ret = public_key_verify_signature(pub, &cert->sig);
+ pr_debug("Cert Verification: %d\n", ret);
+-
+-error_mpi:
+- mpi_free(sig->rsa.s);
+-error:
+- kfree(sig);
+-error_no_sig:
+- crypto_free_shash(tfm);
+-
+- pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+ }
++EXPORT_SYMBOL_GPL(x509_check_signature);
+
+ /*
+ * Attempt to parse a data blob for a key as an X509 certificate.
+@@ -118,8 +129,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ cert->valid_to.tm_mday, cert->valid_to.tm_hour,
+ cert->valid_to.tm_min, cert->valid_to.tm_sec);
+ pr_devel("Cert Signature: %s + %s\n",
+- pkey_algo_name[cert->sig_pkey_algo],
+- pkey_hash_algo_name[cert->sig_hash_algo]);
++ pkey_algo_name[cert->sig.pkey_algo],
++ pkey_hash_algo_name[cert->sig.pkey_hash_algo]);
+
+ if (!cert->fingerprint || !cert->authority) {
+ pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
+--
+1.8.1.2
+
+
+From 2bcc73fb25a5959bd4e6da8af3a4bc8cde807f3d Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:36 +0000
+Subject: [PATCH 12/46] X.509: Check the algorithm IDs obtained from parsing an
+ X.509 certificate
+
+Check that the algorithm IDs obtained from the ASN.1 parse by OID lookup
+corresponds to algorithms that are available to us.
+
+Reported-by: Kees Cook <keescook@chromium.org>
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ crypto/asymmetric_keys/x509_public_key.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index b7c81d8..eb368d4 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -119,6 +119,17 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+
+ pr_devel("Cert Issuer: %s\n", cert->issuer);
+ pr_devel("Cert Subject: %s\n", cert->subject);
++
++ if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
++ cert->sig.pkey_algo >= PKEY_ALGO__LAST ||
++ cert->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
++ !pkey_algo[cert->pub->pkey_algo] ||
++ !pkey_algo[cert->sig.pkey_algo] ||
++ !pkey_hash_algo_name[cert->sig.pkey_hash_algo]) {
++ ret = -ENOPKG;
++ goto error_free_cert;
++ }
++
+ pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
+ pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
+ cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
+--
+1.8.1.2
+
+
+From 65ee135783ff5d7dcec21f89aa8a458928aa8be8 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:37 +0000
+Subject: [PATCH 13/46] X.509: Handle certificates that lack an
+ authorityKeyIdentifier field
+
+Handle certificates that lack an authorityKeyIdentifier field by assuming
+they're self-signed and checking their signatures against themselves.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/x509_public_key.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index eb368d4..0f55e3b 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -143,8 +143,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ pkey_algo_name[cert->sig.pkey_algo],
+ pkey_hash_algo_name[cert->sig.pkey_hash_algo]);
+
+- if (!cert->fingerprint || !cert->authority) {
+- pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
++ if (!cert->fingerprint) {
++ pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
+ cert->subject);
+ ret = -EKEYREJECTED;
+ goto error_free_cert;
+@@ -190,8 +190,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
+ cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
+ cert->pub->id_type = PKEY_ID_X509;
+
+- /* Check the signature on the key */
+- if (strcmp(cert->fingerprint, cert->authority) == 0) {
++ /* Check the signature on the key if it appears to be self-signed */
++ if (!cert->authority ||
++ strcmp(cert->fingerprint, cert->authority) == 0) {
+ ret = x509_check_signature(cert->pub, cert);
+ if (ret < 0)
+ goto error_free_cert;
+--
+1.8.1.2
+
+
+From cda5d188ec1ea1d599d3005017656ea08a50a4c9 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:37 +0000
+Subject: [PATCH 14/46] X.509: Export certificate parse and free functions
+
+Export certificate parse and free functions for use by modules.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+Reviewed-by: Josh Boyer <jwboyer@redhat.com>
+---
+ crypto/asymmetric_keys/x509_cert_parser.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
+index 931f069..9cf0e16 100644
+--- a/crypto/asymmetric_keys/x509_cert_parser.c
++++ b/crypto/asymmetric_keys/x509_cert_parser.c
+@@ -11,6 +11,7 @@
+
+ #define pr_fmt(fmt) "X.509: "fmt
+ #include <linux/kernel.h>
++#include <linux/export.h>
+ #include <linux/slab.h>
+ #include <linux/err.h>
+ #include <linux/oid_registry.h>
+@@ -52,6 +53,7 @@ void x509_free_certificate(struct x509_certificate *cert)
+ kfree(cert);
+ }
+ }
++EXPORT_SYMBOL_GPL(x509_free_certificate);
+
+ /*
+ * Parse an X.509 certificate
+@@ -97,6 +99,7 @@ error_no_ctx:
+ error_no_cert:
+ return ERR_PTR(ret);
+ }
++EXPORT_SYMBOL_GPL(x509_cert_parse);
+
+ /*
+ * Note an OID when we find one for later processing when we know how
+--
+1.8.1.2
+
+
+From 26f7a461be88d22b6ccd357b5bf9784bff53cbad Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:38 +0000
+Subject: [PATCH 15/46] PKCS#7: Implement a parser [RFC 2315]
+
+Implement a parser for a PKCS#7 signed-data message as described in part of
+RFC 2315.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/Kconfig | 9 +
+ crypto/asymmetric_keys/Makefile | 13 ++
+ crypto/asymmetric_keys/pkcs7.asn1 | 127 +++++++++++++
+ crypto/asymmetric_keys/pkcs7_parser.c | 326 ++++++++++++++++++++++++++++++++++
+ crypto/asymmetric_keys/pkcs7_parser.h | 65 +++++++
+ include/linux/oid_registry.h | 1 +
+ 6 files changed, 541 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/pkcs7.asn1
+ create mode 100644 crypto/asymmetric_keys/pkcs7_parser.c
+ create mode 100644 crypto/asymmetric_keys/pkcs7_parser.h
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index 6d2c2ea..413f3f6 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -35,4 +35,13 @@ config X509_CERTIFICATE_PARSER
+ data and provides the ability to instantiate a crypto key from a
+ public key packet found inside the certificate.
+
++config PKCS7_MESSAGE_PARSER
++ tristate "PKCS#7 message parser"
++ depends on X509_CERTIFICATE_PARSER
++ select ASN1
++ select OID_REGISTRY
++ help
++ This option provides support for parsing PKCS#7 format messages for
++ signature data and provides the ability to verify the signature.
++
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 0727204..59d8cad 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -25,3 +25,16 @@ $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
+
+ clean-files += x509-asn1.c x509-asn1.h
+ clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
++
++#
++# PKCS#7 message handling
++#
++obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
++pkcs7_message-y := \
++ pkcs7-asn1.o \
++ pkcs7_parser.o
++
++$(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
++$(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h
++
++clean-files += pkcs7-asn1.c pkcs7-asn1.h
+diff --git a/crypto/asymmetric_keys/pkcs7.asn1 b/crypto/asymmetric_keys/pkcs7.asn1
+new file mode 100644
+index 0000000..7bf91ed
+--- /dev/null
++++ b/crypto/asymmetric_keys/pkcs7.asn1
+@@ -0,0 +1,127 @@
++PKCS7ContentInfo ::= SEQUENCE {
++ contentType ContentType,
++ content [0] EXPLICIT SignedData OPTIONAL
++}
++
++ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
++
++SignedData ::= SEQUENCE {
++ version INTEGER,
++ digestAlgorithms DigestAlgorithmIdentifiers ({ pkcs7_note_digest_algo }),
++ contentInfo ContentInfo,
++ certificates CHOICE {
++ certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
++ certSequence [2] IMPLICIT Certificates
++ } OPTIONAL ({ pkcs7_note_certificate_list }),
++ crls CHOICE {
++ crlSet [1] IMPLICIT CertificateRevocationLists,
++ crlSequence [3] IMPLICIT CRLSequence
++ } OPTIONAL,
++ signerInfos SignerInfos
++}
++
++ContentInfo ::= SEQUENCE {
++ contentType ContentType,
++ content [0] EXPLICIT Data OPTIONAL
++}
++
++Data ::= ANY ({ pkcs7_note_data })
++
++DigestAlgorithmIdentifiers ::= CHOICE {
++ daSet SET OF DigestAlgorithmIdentifier,
++ daSequence SEQUENCE OF DigestAlgorithmIdentifier
++}
++
++DigestAlgorithmIdentifier ::= SEQUENCE {
++ algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
++ parameters ANY OPTIONAL
++}
++
++--
++-- Certificates and certificate lists
++--
++ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate
++
++ExtendedCertificateOrCertificate ::= CHOICE {
++ certificate Certificate, -- X.509
++ extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6
++}
++
++ExtendedCertificate ::= Certificate -- cheating
++
++Certificates ::= SEQUENCE OF Certificate
++
++CertificateRevocationLists ::= SET OF CertificateList
++
++CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly
++
++CRLSequence ::= SEQUENCE OF CertificateList
++
++Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509
++
++--
++-- Signer information
++--
++SignerInfos ::= CHOICE {
++ siSet SET OF SignerInfo,
++ siSequence SEQUENCE OF SignerInfo
++}
++
++SignerInfo ::= SEQUENCE {
++ version INTEGER,
++ issuerAndSerialNumber IssuerAndSerialNumber,
++ digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_note_digest_algo }),
++ authenticatedAttributes CHOICE {
++ aaSet [0] IMPLICIT SetOfAuthenticatedAttribute
++ ({ pkcs7_note_set_of_authattrs }),
++ aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
++ -- Explicit because easier to compute digest on
++ -- sequence of attributes and then reuse encoded
++ -- sequence in aaSequence.
++ } OPTIONAL,
++ digestEncryptionAlgorithm
++ DigestEncryptionAlgorithmIdentifier ({ pkcs7_note_pkey_algo }),
++ encryptedDigest EncryptedDigest,
++ unauthenticatedAttributes CHOICE {
++ uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute,
++ uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
++ } OPTIONAL
++}
++
++IssuerAndSerialNumber ::= SEQUENCE {
++ issuer Name ({ pkcs7_note_issuer }),
++ serialNumber CertificateSerialNumber ({ pkcs7_note_serial })
++}
++
++CertificateSerialNumber ::= INTEGER
++
++SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
++
++AuthenticatedAttribute ::= SEQUENCE {
++ type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
++ values SET OF ANY ({ pkcs7_note_authenticated_attr })
++}
++
++UnauthenticatedAttribute ::= SEQUENCE {
++ type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
++ values SET OF ANY
++}
++
++DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
++ algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
++ parameters ANY OPTIONAL
++}
++
++EncryptedDigest ::= OCTET STRING ({ pkcs7_note_signature })
++
++---
++--- X.500 Name
++---
++Name ::= SEQUENCE OF RelativeDistinguishedName
++
++RelativeDistinguishedName ::= SET OF AttributeValueAssertion
++
++AttributeValueAssertion ::= SEQUENCE {
++ attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }),
++ attributeValue ANY
++}
+diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
+new file mode 100644
+index 0000000..231aff9
+--- /dev/null
++++ b/crypto/asymmetric_keys/pkcs7_parser.c
+@@ -0,0 +1,326 @@
++/* PKCS#7 parser
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "PKCS7: "fmt
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/oid_registry.h>
++#include "public_key.h"
++#include "pkcs7_parser.h"
++#include "pkcs7-asn1.h"
++
++struct pkcs7_parse_context {
++ struct pkcs7_message *msg; /* Message being constructed */
++ struct x509_certificate *certs; /* Certificate cache */
++ struct x509_certificate **ppcerts;
++ unsigned long data; /* Start of data */
++ enum OID last_oid; /* Last OID encountered */
++};
++
++/*
++ * Free a PKCS#7 message
++ */
++void pkcs7_free_message(struct pkcs7_message *pkcs7)
++{
++ struct x509_certificate *cert;
++
++ if (pkcs7) {
++ while (pkcs7->certs) {
++ cert = pkcs7->certs;
++ pkcs7->certs = cert->next;
++ x509_free_certificate(cert);
++ }
++ while (pkcs7->crl) {
++ cert = pkcs7->crl;
++ pkcs7->crl = cert->next;
++ x509_free_certificate(cert);
++ }
++ kfree(pkcs7->sig.digest);
++ mpi_free(pkcs7->sig.mpi[0]);
++ kfree(pkcs7);
++ }
++}
++EXPORT_SYMBOL_GPL(pkcs7_free_message);
++
++/*
++ * Parse a PKCS#7 message
++ */
++struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
++{
++ struct pkcs7_parse_context *ctx;
++ struct pkcs7_message *msg;
++ long ret;
++
++ ret = -ENOMEM;
++ msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
++ if (!msg)
++ goto error_no_sig;
++ ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
++ if (!ctx)
++ goto error_no_ctx;
++
++ ctx->msg = msg;
++ ctx->data = (unsigned long)data;
++ ctx->ppcerts = &ctx->certs;
++
++ /* Attempt to decode the signature */
++ ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
++ if (ret < 0)
++ goto error_decode;
++
++ while (ctx->certs) {
++ struct x509_certificate *cert = ctx->certs;
++ ctx->certs = cert->next;
++ x509_free_certificate(cert);
++ }
++ kfree(ctx);
++ return msg;
++
++error_decode:
++ kfree(ctx);
++error_no_ctx:
++ pkcs7_free_message(msg);
++error_no_sig:
++ return ERR_PTR(ret);
++}
++EXPORT_SYMBOL_GPL(pkcs7_parse_message);
++
++/*
++ * Note an OID when we find one for later processing when we know how
++ * to interpret it.
++ */
++int pkcs7_note_OID(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++
++ ctx->last_oid = look_up_OID(value, vlen);
++ if (ctx->last_oid == OID__NR) {
++ char buffer[50];
++ sprint_oid(value, vlen, buffer, sizeof(buffer));
++ printk("PKCS7: Unknown OID: [%lu] %s\n",
++ (unsigned long)value - ctx->data, buffer);
++ }
++ return 0;
++}
++
++/*
++ * Note the digest algorithm for the signature.
++ */
++int pkcs7_note_digest_algo(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++
++ switch (ctx->last_oid) {
++ case OID_md4:
++ ctx->msg->sig.pkey_hash_algo = PKEY_HASH_MD4;
++ break;
++ case OID_md5:
++ ctx->msg->sig.pkey_hash_algo = PKEY_HASH_MD5;
++ break;
++ case OID_sha1:
++ ctx->msg->sig.pkey_hash_algo = PKEY_HASH_SHA1;
++ break;
++ case OID_sha256:
++ ctx->msg->sig.pkey_hash_algo = PKEY_HASH_SHA256;
++ break;
++ default:
++ printk("Unsupported digest algo: %u\n", ctx->last_oid);
++ return -ENOPKG;
++ }
++ return 0;
++}
++
++/*
++ * Note the public key algorithm for the signature.
++ */
++int pkcs7_note_pkey_algo(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++
++ switch (ctx->last_oid) {
++ case OID_rsaEncryption:
++ ctx->msg->sig.pkey_algo = PKEY_ALGO_RSA;
++ break;
++ default:
++ printk("Unsupported pkey algo: %u\n", ctx->last_oid);
++ return -ENOPKG;
++ }
++ return 0;
++}
++
++/*
++ * Extract a certificate and store it in the context.
++ */
++int pkcs7_extract_cert(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++ struct x509_certificate *cert;
++
++ if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
++ pr_debug("Cert began with tag %02x at %lu\n",
++ tag, (unsigned long)ctx - ctx->data);
++ return -EBADMSG;
++ }
++
++ /* We have to correct for the header so that the X.509 parser can start
++ * from the beginning. Note that since X.509 stipulates DER, there
++ * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
++ * stipulates BER).
++ */
++ value -= hdrlen;
++ vlen += hdrlen;
++
++ if (((u8*)value)[1] == 0x80)
++ vlen += 2; /* Indefinite length - there should be an EOC */
++
++ cert = x509_cert_parse(value, vlen);
++ if (IS_ERR(cert))
++ return PTR_ERR(cert);
++
++ pr_debug("Got cert for %s\n", cert->subject);
++ pr_debug("- fingerprint %s\n", cert->fingerprint);
++
++ *ctx->ppcerts = cert;
++ ctx->ppcerts = &cert->next;
++ return 0;
++}
++
++/*
++ * Save the certificate list
++ */
++int pkcs7_note_certificate_list(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++
++ pr_devel("Got cert list (%02x)\n", tag);
++
++ *ctx->ppcerts = ctx->msg->certs;
++ ctx->msg->certs = ctx->certs;
++ ctx->certs = NULL;
++ ctx->ppcerts = &ctx->certs;
++ return 0;
++}
++
++/*
++ * Extract the data from the signature and store that and its content type OID
++ * in the context.
++ */
++int pkcs7_note_data(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++
++ pr_debug("Got data\n");
++
++ ctx->msg->data = value;
++ ctx->msg->data_len = vlen;
++ ctx->msg->data_hdrlen = hdrlen;
++ ctx->msg->data_type = ctx->last_oid;
++ return 0;
++}
++
++/*
++ * Parse authenticated attributes
++ */
++int pkcs7_note_authenticated_attr(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++
++ pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
++
++ switch (ctx->last_oid) {
++ case OID_messageDigest:
++ if (tag != ASN1_OTS)
++ return -EBADMSG;
++ ctx->msg->msgdigest = value;
++ ctx->msg->msgdigest_len = vlen;
++ return 0;
++ default:
++ return 0;
++ }
++}
++
++/*
++ * Note the set of auth attributes for digestion purposes [RFC2315 9.3]
++ */
++int pkcs7_note_set_of_authattrs(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++
++ /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
++ ctx->msg->authattrs = value - (hdrlen - 1);
++ ctx->msg->authattrs_len = vlen + (hdrlen - 1);
++ return 0;
++}
++
++/*
++ * Note the issuing certificate serial number
++ */
++int pkcs7_note_serial(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++ ctx->msg->raw_serial = value;
++ ctx->msg->raw_serial_size = vlen;
++ return 0;
++}
++
++/*
++ * Note the issuer's name
++ */
++int pkcs7_note_issuer(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++ ctx->msg->raw_issuer = value;
++ ctx->msg->raw_issuer_size = vlen;
++ return 0;
++}
++
++/*
++ * Note the signature data
++ */
++int pkcs7_note_signature(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pkcs7_parse_context *ctx = context;
++ MPI mpi;
++
++ BUG_ON(ctx->msg->sig.pkey_algo != PKEY_ALGO_RSA);
++
++ mpi = mpi_read_raw_data(value, vlen);
++ if (!mpi)
++ return -ENOMEM;
++
++ ctx->msg->sig.mpi[0] = mpi;
++ ctx->msg->sig.nr_mpi = 1;
++ return 0;
++}
+diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
+new file mode 100644
+index 0000000..5415857
+--- /dev/null
++++ b/crypto/asymmetric_keys/pkcs7_parser.h
+@@ -0,0 +1,65 @@
++/* PKCS#7 crypto data parser internal definitions
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#include <linux/oid_registry.h>
++#include "x509_parser.h"
++
++#define kenter(FMT, ...) \
++ pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
++#define kleave(FMT, ...) \
++ pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
++
++struct pkcs7_message {
++ struct x509_certificate *certs; /* Certificate list */
++ struct x509_certificate *crl; /* Revocation list */
++ struct x509_certificate *signer; /* Signing certificate (in ->certs) */
++
++ /* Content Data (or NULL) */
++ enum OID data_type; /* Type of Data */
++ size_t data_len; /* Length of Data */
++ size_t data_hdrlen; /* Length of Data ASN.1 header */
++ const void *data; /* Content Data (or 0) */
++
++ /* Message digest - the digest of the Content Data (or NULL) */
++ const void *msgdigest;
++ unsigned msgdigest_len;
++
++ /* Authenticated Attribute data (or NULL) */
++ unsigned authattrs_len;
++ const void *authattrs;
++
++ /* Issuing cert serial number and issuer's name */
++ const void *raw_serial;
++ unsigned raw_serial_size;
++ unsigned raw_issuer_size;
++ const void *raw_issuer;
++
++ /* Message signature.
++ *
++ * This contains the generated digest of _either_ the Content Data or
++ * the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
++ * the attributes contains the digest of the the Content Data within
++ * it.
++ */
++ struct public_key_signature sig;
++};
++
++/*
++ * pkcs7_parser.c
++ */
++extern struct pkcs7_message *pkcs7_parse_message(const void *data,
++ size_t datalen);
++extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
++
++/*
++ * pkcs7_verify.c
++ */
++extern int pkcs7_verify(struct pkcs7_message *pkcs7);
+diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
+index 6926db7..edeff85 100644
+--- a/include/linux/oid_registry.h
++++ b/include/linux/oid_registry.h
+@@ -55,6 +55,7 @@ enum OID {
+ OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
+ OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
+ OID_sha1, /* 1.3.14.3.2.26 */
++ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
+
+ /* Distinguished Name attribute IDs [RFC 2256] */
+ OID_commonName, /* 2.5.4.3 */
+--
+1.8.1.2
+
+
+From e99cd6117fce747b0867eac7f09369b6fbfe1fbc Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:38 +0000
+Subject: [PATCH 16/46] PKCS#7: Digest the data in a signed-data message
+
+Digest the data in a PKCS#7 signed-data message and attach to the
+public_key_signature struct contained in the pkcs7_message struct.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/Makefile | 3 +-
+ crypto/asymmetric_keys/pkcs7_verify.c | 134 ++++++++++++++++++++++++++++++++++
+ 2 files changed, 136 insertions(+), 1 deletion(-)
+ create mode 100644 crypto/asymmetric_keys/pkcs7_verify.c
+
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 59d8cad..b6b39e7 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -32,7 +32,8 @@ clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h
+ obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
+ pkcs7_message-y := \
+ pkcs7-asn1.o \
+- pkcs7_parser.o
++ pkcs7_parser.o \
++ pkcs7_verify.o
+
+ $(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
+ $(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h
+diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
+new file mode 100644
+index 0000000..2f9f26c
+--- /dev/null
++++ b/crypto/asymmetric_keys/pkcs7_verify.c
+@@ -0,0 +1,134 @@
++/* Verify the signature on a PKCS#7 message.
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "PKCS7: "fmt
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/asn1.h>
++#include <crypto/hash.h>
++#include "public_key.h"
++#include "pkcs7_parser.h"
++
++/*
++ * Digest the relevant parts of the PKCS#7 data
++ */
++static int pkcs7_digest(struct pkcs7_message *pkcs7)
++{
++ struct crypto_shash *tfm;
++ struct shash_desc *desc;
++ size_t digest_size, desc_size;
++ void *digest;
++ int ret;
++
++ kenter(",%u", pkcs7->sig.pkey_hash_algo);
++
++ if (pkcs7->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
++ !pkey_hash_algo_name[pkcs7->sig.pkey_hash_algo])
++ return -ENOPKG;
++
++ /* Allocate the hashing algorithm we're going to need and find out how
++ * big the hash operational data will be.
++ */
++ tfm = crypto_alloc_shash(pkey_hash_algo_name[pkcs7->sig.pkey_hash_algo],
++ 0, 0);
++ if (IS_ERR(tfm))
++ return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
++
++ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
++ pkcs7->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
++
++ ret = -ENOMEM;
++ digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
++ if (!digest)
++ goto error_no_desc;
++
++ desc = digest + digest_size;
++ desc->tfm = tfm;
++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++
++ /* Digest the message [RFC2315 9.3] */
++ ret = crypto_shash_init(desc);
++ if (ret < 0)
++ goto error;
++ ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
++ if (ret < 0)
++ goto error;
++ pr_devel("MsgDigest = [%*ph]\n", 8, digest);
++
++ /* However, if there are authenticated attributes, there must be a
++ * message digest attribute amongst them which corresponds to the
++ * digest we just calculated.
++ */
++ if (pkcs7->msgdigest) {
++ u8 tag;
++
++ if (pkcs7->msgdigest_len != pkcs7->sig.digest_size) {
++ pr_debug("Invalid digest size (%u)\n",
++ pkcs7->msgdigest_len);
++ ret = -EBADMSG;
++ goto error;
++ }
++
++ if (memcmp(digest, pkcs7->msgdigest, pkcs7->msgdigest_len) != 0) {
++ pr_debug("Message digest doesn't match\n");
++ ret = -EKEYREJECTED;
++ goto error;
++ }
++
++ /* We then calculate anew, using the authenticated attributes
++ * as the contents of the digest instead. Note that we need to
++ * convert the attributes from a CONT.0 into a SET before we
++ * hash it.
++ */
++ memset(digest, 0, pkcs7->sig.digest_size);
++
++ ret = crypto_shash_init(desc);
++ if (ret < 0)
++ goto error;
++ tag = ASN1_CONS_BIT | ASN1_SET;
++ ret = crypto_shash_update(desc, &tag, 1);
++ if (ret < 0)
++ goto error;
++ ret = crypto_shash_finup(desc, pkcs7->authattrs,
++ pkcs7->authattrs_len, digest);
++ if (ret < 0)
++ goto error;
++ pr_devel("AADigest = [%*ph]\n", 8, digest);
++ }
++
++ pkcs7->sig.digest = digest;
++ digest = NULL;
++
++error:
++ kfree(digest);
++error_no_desc:
++ crypto_free_shash(tfm);
++ kleave(" = %d\n", ret);
++ return ret;
++}
++
++/*
++ * Verify a PKCS#7 message
++ */
++int pkcs7_verify(struct pkcs7_message *pkcs7)
++{
++ int ret;
++
++ /* First of all, digest the data in the PKCS#7 message */
++ ret = pkcs7_digest(pkcs7);
++ if (ret < 0)
++ return ret;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(pkcs7_verify);
+--
+1.8.1.2
+
+
+From c803112feb230b4e5d5a91f0a358007a397f85d3 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:39 +0000
+Subject: [PATCH 17/46] PKCS#7: Find the right key in the PKCS#7 key list and
+ verify the signature
+
+Find the appropriate key in the PKCS#7 key list and verify the signature with
+it. There may be several keys in there forming a chain. Any link in that
+chain or the root of that chain may be in our keyrings.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/pkcs7_verify.c | 61 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 61 insertions(+)
+
+diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
+index 2f9f26c..3f6f0e2 100644
+--- a/crypto/asymmetric_keys/pkcs7_verify.c
++++ b/crypto/asymmetric_keys/pkcs7_verify.c
+@@ -118,6 +118,53 @@ error_no_desc:
+ }
+
+ /*
++ * Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
++ * uses the issuer's name and the issuing certificate serial number for
++ * matching purposes. These must match the certificate issuer's name (not
++ * subject's name) and the certificate serial number [RFC 2315 6.7].
++ */
++static int pkcs7_find_key(struct pkcs7_message *pkcs7)
++{
++ struct x509_certificate *x509;
++
++ kenter("%u,%u", pkcs7->raw_serial_size, pkcs7->raw_issuer_size);
++
++ for (x509 = pkcs7->certs; x509; x509 = x509->next) {
++ pr_devel("- x509 %u,%u\n",
++ x509->raw_serial_size, x509->raw_issuer_size);
++
++ /* I'm _assuming_ that the generator of the PKCS#7 message will
++ * encode the fields from the X.509 cert in the same way in the
++ * PKCS#7 message - but I can't be 100% sure of that. It's
++ * possible this will need element-by-element comparison.
++ */
++ if (x509->raw_serial_size != pkcs7->raw_serial_size ||
++ memcmp(x509->raw_serial, pkcs7->raw_serial,
++ pkcs7->raw_serial_size) != 0)
++ continue;
++ pr_devel("Found cert serial match\n");
++
++ if (x509->raw_issuer_size != pkcs7->raw_issuer_size ||
++ memcmp(x509->raw_issuer, pkcs7->raw_issuer,
++ pkcs7->raw_issuer_size) != 0) {
++ pr_warn("X.509 subject and PKCS#7 issuer don't match\n");
++ continue;
++ }
++
++ if (x509->pub->pkey_algo != pkcs7->sig.pkey_algo) {
++ pr_warn("X.509 algo and PKCS#7 sig algo don't match\n");
++ continue;
++ }
++
++ pkcs7->signer = x509;
++ return 0;
++ }
++ pr_warn("Issuing X.509 cert not found (#%*ph)\n",
++ pkcs7->raw_serial_size, pkcs7->raw_serial);
++ return -ENOKEY;
++}
++
++/*
+ * Verify a PKCS#7 message
+ */
+ int pkcs7_verify(struct pkcs7_message *pkcs7)
+@@ -129,6 +176,20 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
+ if (ret < 0)
+ return ret;
+
++ /* Find the key for the message signature */
++ ret = pkcs7_find_key(pkcs7);
++ if (ret < 0)
++ return ret;
++
++ pr_devel("Found X.509 cert\n");
++
++ /* Verify the PKCS#7 binary against the key */
++ ret = public_key_verify_signature(pkcs7->signer->pub, &pkcs7->sig);
++ if (ret < 0)
++ return ret;
++
++ pr_devel("Verified signature\n");
++
+ return 0;
+ }
+ EXPORT_SYMBOL_GPL(pkcs7_verify);
+--
+1.8.1.2
+
+
+From f54c32c382837a59ee4e3e4d381b4a97301d5960 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:39 +0000
+Subject: [PATCH 18/46] PKCS#7: Verify internal certificate chain
+
+Verify certificate chain in the X.509 certificates contained within the PKCS#7
+message as far as possible. If any signature that we should be able to verify
+fails, we reject the whole lot.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/pkcs7_verify.c | 67 ++++++++++++++++++++++++++++++++++-
+ crypto/asymmetric_keys/x509_parser.h | 1 +
+ 2 files changed, 67 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
+index 3f6f0e2..b3774bd 100644
+--- a/crypto/asymmetric_keys/pkcs7_verify.c
++++ b/crypto/asymmetric_keys/pkcs7_verify.c
+@@ -165,6 +165,70 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7)
+ }
+
+ /*
++ * Verify the internal certificate chain as best we can.
++ */
++static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7)
++{
++ struct x509_certificate *x509 = pkcs7->signer, *p;
++ int ret;
++
++ kenter("");
++
++ for (;;) {
++ pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
++ ret = x509_get_sig_params(x509);
++ if (ret < 0)
++ return ret;
++
++ if (x509->issuer)
++ pr_debug("- issuer %s\n", x509->issuer);
++ if (x509->authority)
++ pr_debug("- authkeyid %s\n", x509->authority);
++
++ if (!x509->authority ||
++ (x509->subject &&
++ strcmp(x509->subject, x509->authority) == 0)) {
++ /* If there's no authority certificate specified, then
++ * the certificate must be self-signed and is the root
++ * of the chain. Likewise if the cert is its own
++ * authority.
++ */
++ pr_debug("- no auth?\n");
++ if (x509->raw_subject_size != x509->raw_issuer_size ||
++ memcmp(x509->raw_subject, x509->raw_issuer,
++ x509->raw_issuer_size) != 0)
++ return 0;
++
++ ret = x509_check_signature(x509->pub, x509);
++ if (ret < 0)
++ return ret;
++ x509->signer = x509;
++ pr_debug("- self-signed\n");
++ return 0;
++ }
++
++ for (p = pkcs7->certs; p; p = p->next)
++ if (!p->signer &&
++ p->raw_subject_size == x509->raw_issuer_size &&
++ strcmp(p->fingerprint, x509->authority) == 0 &&
++ memcmp(p->raw_subject, x509->raw_issuer,
++ x509->raw_issuer_size) == 0)
++ goto found_issuer;
++ pr_debug("- top\n");
++ return 0;
++
++ found_issuer:
++ pr_debug("- issuer %s\n", p->subject);
++ ret = x509_check_signature(p->pub, x509);
++ if (ret < 0)
++ return ret;
++ x509->signer = p;
++ x509 = p;
++ might_sleep();
++ }
++}
++
++/*
+ * Verify a PKCS#7 message
+ */
+ int pkcs7_verify(struct pkcs7_message *pkcs7)
+@@ -190,6 +254,7 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
+
+ pr_devel("Verified signature\n");
+
+- return 0;
++ /* Verify the internal certificate chain */
++ return pkcs7_verify_sig_chain(pkcs7);
+ }
+ EXPORT_SYMBOL_GPL(pkcs7_verify);
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+index 6b1d877..5e35fba 100644
+--- a/crypto/asymmetric_keys/x509_parser.h
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -14,6 +14,7 @@
+
+ struct x509_certificate {
+ struct x509_certificate *next;
++ const struct x509_certificate *signer; /* Certificate that signed this one */
+ struct public_key *pub; /* Public key details */
+ char *issuer; /* Name of certificate issuer */
+ char *subject; /* Name of certificate subject */
+--
+1.8.1.2
+
+
+From 07951d065ba4cc729217477486e5d1eaa4288762 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:42 +0000
+Subject: [PATCH 19/46] PKCS#7: Find intersection between PKCS#7 message and
+ known, trusted keys
+
+Find the intersection between the X.509 certificate chain contained in a PKCS#7
+message and a set of keys that we already know and trust.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/Makefile | 1 +
+ crypto/asymmetric_keys/pkcs7_parser.h | 7 ++
+ crypto/asymmetric_keys/pkcs7_trust.c | 149 ++++++++++++++++++++++++++++++++++
+ 3 files changed, 157 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/pkcs7_trust.c
+
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index b6b39e7..d63cb43 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -33,6 +33,7 @@ obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
+ pkcs7_message-y := \
+ pkcs7-asn1.o \
+ pkcs7_parser.o \
++ pkcs7_trust.o \
+ pkcs7_verify.o
+
+ $(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
+diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
+index 5415857..ffa72dc 100644
+--- a/crypto/asymmetric_keys/pkcs7_parser.h
++++ b/crypto/asymmetric_keys/pkcs7_parser.h
+@@ -60,6 +60,13 @@ extern struct pkcs7_message *pkcs7_parse_message(const void *data,
+ extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
+
+ /*
++ * pkcs7_trust.c
++ */
++extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
++ struct key *trust_keyring,
++ bool *_trusted);
++
++/*
+ * pkcs7_verify.c
+ */
+ extern int pkcs7_verify(struct pkcs7_message *pkcs7);
+diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
+new file mode 100644
+index 0000000..cc226f5
+--- /dev/null
++++ b/crypto/asymmetric_keys/pkcs7_trust.c
+@@ -0,0 +1,149 @@
++/* Validate the trust chain of a PKCS#7 message.
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "PKCS7: "fmt
++#include <linux/kernel.h>
++#include <linux/export.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/asn1.h>
++#include <linux/key.h>
++#include <keys/asymmetric-type.h>
++#include "public_key.h"
++#include "pkcs7_parser.h"
++
++/*
++ * Request an asymmetric key.
++ */
++static struct key *pkcs7_request_asymmetric_key(
++ struct key *keyring,
++ const char *signer, size_t signer_len,
++ const char *authority, size_t auth_len)
++{
++ key_ref_t key;
++ char *id;
++
++ kenter(",%zu,,%zu", signer_len, auth_len);
++
++ /* Construct an identifier. */
++ id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
++ if (!id)
++ return ERR_PTR(-ENOMEM);
++
++ memcpy(id, signer, signer_len);
++ id[signer_len + 0] = ':';
++ id[signer_len + 1] = ' ';
++ memcpy(id + signer_len + 2, authority, auth_len);
++ id[signer_len + 2 + auth_len] = 0;
++
++ pr_debug("Look up: \"%s\"\n", id);
++
++ key = keyring_search(make_key_ref(keyring, 1),
++ &key_type_asymmetric, id);
++ if (IS_ERR(key))
++ pr_debug("Request for module key '%s' err %ld\n",
++ id, PTR_ERR(key));
++ kfree(id);
++
++ if (IS_ERR(key)) {
++ switch (PTR_ERR(key)) {
++ /* Hide some search errors */
++ case -EACCES:
++ case -ENOTDIR:
++ case -EAGAIN:
++ return ERR_PTR(-ENOKEY);
++ default:
++ return ERR_CAST(key);
++ }
++ }
++
++ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
++ return key_ref_to_ptr(key);
++}
++
++/*
++ * Validate that the certificate chain inside the PKCS#7 message intersects
++ * keys we already know and trust.
++ */
++int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
++ struct key *trust_keyring,
++ bool *_trusted)
++{
++ struct public_key_signature *sig = &pkcs7->sig;
++ struct x509_certificate *x509, *last = NULL;
++ struct key *key;
++ bool trusted;
++ int ret;
++
++ kenter("");
++
++ for (x509 = pkcs7->signer; x509; x509 = x509->next) {
++ /* Look to see if this certificate is present in the trusted
++ * keys.
++ */
++ key = pkcs7_request_asymmetric_key(
++ trust_keyring,
++ x509->subject, strlen(x509->subject),
++ x509->fingerprint, strlen(x509->fingerprint));
++ if (!IS_ERR(key))
++ /* One of the X.509 certificates in the PKCS#7 message
++ * is apparently the same as one we already trust.
++ * Verify that the trusted variant can also validate
++ * the signature on the descendent.
++ */
++ goto matched;
++ if (key == ERR_PTR(-ENOMEM))
++ return -ENOMEM;
++
++ /* Self-signed certificates form roots of their own, and if we
++ * don't know them, then we can't accept them.
++ */
++ if (x509->next == x509) {
++ kleave(" = -EKEYREJECTED [unknown self-signed]");
++ return -EKEYREJECTED;
++ }
++
++ might_sleep();
++ last = x509;
++ sig = &last->sig;
++ }
++
++ /* No match - see if the root certificate has a signer amongst the
++ * trusted keys.
++ */
++ if (!last || !last->issuer || !last->authority) {
++ kleave(" = -EKEYREJECTED [no backref]");
++ return -EKEYREJECTED;
++ }
++
++ key = pkcs7_request_asymmetric_key(
++ trust_keyring,
++ last->issuer, strlen(last->issuer),
++ last->authority, strlen(last->authority));
++ if (IS_ERR(key))
++ return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -EKEYREJECTED;
++
++matched:
++ ret = verify_signature(key, sig);
++ trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
++ key_put(key);
++ if (ret < 0) {
++ if (ret == -ENOMEM)
++ return ret;
++ kleave(" = -EKEYREJECTED [verify %d]", ret);
++ return -EKEYREJECTED;
++ }
++
++ *_trusted = trusted;
++ kleave(" = 0");
++ return 0;
++}
++EXPORT_SYMBOL_GPL(pkcs7_validate_trust);
+--
+1.8.1.2
+
+
+From 29267ccd926681bbf19594da3e920ff07f70f172 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:39 +0000
+Subject: [PATCH 20/46] Provide PE binary definitions
+
+Provide some PE binary structural and constant definitions as taken from the
+pesign package sources.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ include/linux/pe.h | 448 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 448 insertions(+)
+ create mode 100644 include/linux/pe.h
+
+diff --git a/include/linux/pe.h b/include/linux/pe.h
+new file mode 100644
+index 0000000..9234aef
+--- /dev/null
++++ b/include/linux/pe.h
+@@ -0,0 +1,448 @@
++/*
++ * Copyright 2011 Red Hat, Inc.
++ * All rights reserved.
++ *
++ * 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.
++ *
++ * This program 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, see <http://www.gnu.org/licenses/>.
++ *
++ * Author(s): Peter Jones <pjones@redhat.com>
++ */
++#ifndef __LINUX_PE_H
++#define __LINUX_PE_H
++
++#include <linux/types.h>
++
++#define MZ_MAGIC 0x5a4d /* "MZ" */
++
++struct mz_hdr {
++ uint16_t magic; /* MZ_MAGIC */
++ uint16_t lbsize; /* size of last used block */
++ uint16_t blocks; /* pages in file, 0x3 */
++ uint16_t relocs; /* relocations */
++ uint16_t hdrsize; /* header size in "paragraphs" */
++ uint16_t min_extra_pps; /* .bss */
++ uint16_t max_extra_pps; /* runtime limit for the arena size */
++ uint16_t ss; /* relative stack segment */
++ uint16_t sp; /* initial %sp register */
++ uint16_t checksum; /* word checksum */
++ uint16_t ip; /* initial %ip register */
++ uint16_t cs; /* initial %cs relative to load segment */
++ uint16_t reloc_table_offset; /* offset of the first relocation */
++ uint16_t overlay_num; /* overlay number. set to 0. */
++ uint16_t reserved0[4]; /* reserved */
++ uint16_t oem_id; /* oem identifier */
++ uint16_t oem_info; /* oem specific */
++ uint16_t reserved1[10]; /* reserved */
++ uint32_t peaddr; /* address of pe header */
++ char message[64]; /* message to print */
++};
++
++struct mz_reloc {
++ uint16_t offset;
++ uint16_t segment;
++};
++
++#define PE_MAGIC 0x00004550 /* "PE\0\0" */
++#define PE_OPT_MAGIC_PE32 0x010b
++#define PE_OPT_MAGIC_PE32_ROM 0x0107
++#define PE_OPT_MAGIC_PE32PLUS 0x020b
++
++/* machine type */
++#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000
++#define IMAGE_FILE_MACHINE_AM33 0x01d3
++#define IMAGE_FILE_MACHINE_AMD64 0x8664
++#define IMAGE_FILE_MACHINE_ARM 0x01c0
++#define IMAGE_FILE_MACHINE_ARMV7 0x01c4
++#define IMAGE_FILE_MACHINE_EBC 0x0ebc
++#define IMAGE_FILE_MACHINE_I386 0x014c
++#define IMAGE_FILE_MACHINE_IA64 0x0200
++#define IMAGE_FILE_MACHINE_M32R 0x9041
++#define IMAGE_FILE_MACHINE_MIPS16 0x0266
++#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366
++#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466
++#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
++#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
++#define IMAGE_FILE_MACHINE_R4000 0x0166
++#define IMAGE_FILE_MACHINE_SH3 0x01a2
++#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
++#define IMAGE_FILE_MACHINE_SH3E 0x01a4
++#define IMAGE_FILE_MACHINE_SH4 0x01a6
++#define IMAGE_FILE_MACHINE_SH5 0x01a8
++#define IMAGE_FILE_MACHINE_THUMB 0x01c2
++#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
++
++/* flags */
++#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
++#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
++#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
++#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
++#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
++#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
++#define IMAGE_FILE_16BIT_MACHINE 0x0040
++#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
++#define IMAGE_FILE_32BIT_MACHINE 0x0100
++#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
++#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
++#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
++#define IMAGE_FILE_SYSTEM 0x1000
++#define IMAGE_FILE_DLL 0x2000
++#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
++#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
++
++struct pe_hdr {
++ uint32_t magic; /* PE magic */
++ uint16_t machine; /* machine type */
++ uint16_t sections; /* number of sections */
++ uint32_t timestamp; /* time_t */
++ uint32_t symbol_table; /* symbol table offset */
++ uint32_t symbols; /* number of symbols */
++ uint16_t opt_hdr_size; /* size of optional header */
++ uint16_t flags; /* flags */
++};
++
++#define IMAGE_FILE_OPT_ROM_MAGIC 0x107
++#define IMAGE_FILE_OPT_PE32_MAGIC 0x10b
++#define IMAGE_FILE_OPT_PE32_PLUS_MAGIC 0x20b
++
++#define IMAGE_SUBSYSTEM_UNKNOWN 0
++#define IMAGE_SUBSYSTEM_NATIVE 1
++#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
++#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
++#define IMAGE_SUBSYSTEM_POSIX_CUI 7
++#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
++#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
++#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
++#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
++#define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13
++#define IMAGE_SUBSYSTEM_XBOX 14
++
++#define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040
++#define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080
++#define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100
++#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200
++#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
++#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
++#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
++#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
++
++/* the fact that pe32 isn't padded where pe32+ is 64-bit means union won't
++ * work right. vomit. */
++struct pe32_opt_hdr {
++ /* "standard" header */
++ uint16_t magic; /* file type */
++ uint8_t ld_major; /* linker major version */
++ uint8_t ld_minor; /* linker minor version */
++ uint32_t text_size; /* size of text section(s) */
++ uint32_t data_size; /* size of data section(s) */
++ uint32_t bss_size; /* size of bss section(s) */
++ uint32_t entry_point; /* file offset of entry point */
++ uint32_t code_base; /* relative code addr in ram */
++ uint32_t data_base; /* relative data addr in ram */
++ /* "windows" header */
++ uint32_t image_base; /* preferred load address */
++ uint32_t section_align; /* alignment in bytes */
++ uint32_t file_align; /* file alignment in bytes */
++ uint16_t os_major; /* major OS version */
++ uint16_t os_minor; /* minor OS version */
++ uint16_t image_major; /* major image version */
++ uint16_t image_minor; /* minor image version */
++ uint16_t subsys_major; /* major subsystem version */
++ uint16_t subsys_minor; /* minor subsystem version */
++ uint32_t win32_version; /* reserved, must be 0 */
++ uint32_t image_size; /* image size */
++ uint32_t header_size; /* header size rounded up to
++ file_align */
++ uint32_t csum; /* checksum */
++ uint16_t subsys; /* subsystem */
++ uint16_t dll_flags; /* more flags! */
++ uint32_t stack_size_req;/* amt of stack requested */
++ uint32_t stack_size; /* amt of stack required */
++ uint32_t heap_size_req; /* amt of heap requested */
++ uint32_t heap_size; /* amt of heap required */
++ uint32_t loader_flags; /* reserved, must be 0 */
++ uint32_t data_dirs; /* number of data dir entries */
++};
++
++struct pe32plus_opt_hdr {
++ uint16_t magic; /* file type */
++ uint8_t ld_major; /* linker major version */
++ uint8_t ld_minor; /* linker minor version */
++ uint32_t text_size; /* size of text section(s) */
++ uint32_t data_size; /* size of data section(s) */
++ uint32_t bss_size; /* size of bss section(s) */
++ uint32_t entry_point; /* file offset of entry point */
++ uint32_t code_base; /* relative code addr in ram */
++ /* "windows" header */
++ uint64_t image_base; /* preferred load address */
++ uint32_t section_align; /* alignment in bytes */
++ uint32_t file_align; /* file alignment in bytes */
++ uint16_t os_major; /* major OS version */
++ uint16_t os_minor; /* minor OS version */
++ uint16_t image_major; /* major image version */
++ uint16_t image_minor; /* minor image version */
++ uint16_t subsys_major; /* major subsystem version */
++ uint16_t subsys_minor; /* minor subsystem version */
++ uint32_t win32_version; /* reserved, must be 0 */
++ uint32_t image_size; /* image size */
++ uint32_t header_size; /* header size rounded up to
++ file_align */
++ uint32_t csum; /* checksum */
++ uint16_t subsys; /* subsystem */
++ uint16_t dll_flags; /* more flags! */
++ uint64_t stack_size_req;/* amt of stack requested */
++ uint64_t stack_size; /* amt of stack required */
++ uint64_t heap_size_req; /* amt of heap requested */
++ uint64_t heap_size; /* amt of heap required */
++ uint32_t loader_flags; /* reserved, must be 0 */
++ uint32_t data_dirs; /* number of data dir entries */
++};
++
++struct data_dirent {
++ uint32_t virtual_address; /* relative to load address */
++ uint32_t size;
++};
++
++struct data_directory {
++ struct data_dirent exports; /* .edata */
++ struct data_dirent imports; /* .idata */
++ struct data_dirent resources; /* .rsrc */
++ struct data_dirent exceptions; /* .pdata */
++ struct data_dirent certs; /* certs */
++ struct data_dirent base_relocations; /* .reloc */
++ struct data_dirent debug; /* .debug */
++ struct data_dirent arch; /* reservered */
++ struct data_dirent global_ptr; /* global pointer reg. Size=0 */
++ struct data_dirent tls; /* .tls */
++ struct data_dirent load_config; /* load configuration structure */
++ struct data_dirent bound_imports; /* no idea */
++ struct data_dirent import_addrs; /* import address table */
++ struct data_dirent delay_imports; /* delay-load import table */
++ struct data_dirent clr_runtime_hdr; /* .cor (object only) */
++ struct data_dirent reserved;
++};
++
++struct section_header {
++ char name[8]; /* name or "/12\0" string tbl offset */
++ uint32_t virtual_size; /* size of loaded section in ram */
++ uint32_t virtual_address; /* relative virtual address */
++ uint32_t raw_data_size; /* size of the section */
++ uint32_t data_addr; /* file pointer to first page of sec */
++ uint32_t relocs; /* file pointer to relocation entries */
++ uint32_t line_numbers; /* line numbers! */
++ uint16_t num_relocs; /* number of relocations */
++ uint16_t num_lin_numbers; /* srsly. */
++ uint32_t flags;
++};
++
++/* they actually defined 0x00000000 as well, but I think we'll skip that one. */
++#define IMAGE_SCN_RESERVED_0 0x00000001
++#define IMAGE_SCN_RESERVED_1 0x00000002
++#define IMAGE_SCN_RESERVED_2 0x00000004
++#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* don't pad - obsolete */
++#define IMAGE_SCN_RESERVED_3 0x00000010
++#define IMAGE_SCN_CNT_CODE 0x00000020 /* .text */
++#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */
++#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */
++#define IMAGE_SCN_LNK_OTHER 0x00000100 /* reserved */
++#define IMAGE_SCN_LNK_INFO 0x00000200 /* .drectve comments */
++#define IMAGE_SCN_RESERVED_4 0x00000400
++#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* .o only - scn to be rm'd*/
++#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* .o only - COMDAT data */
++#define IMAGE_SCN_RESERVED_5 0x00002000 /* spec omits this */
++#define IMAGE_SCN_RESERVED_6 0x00004000 /* spec omits this */
++#define IMAGE_SCN_GPREL 0x00008000 /* global pointer referenced data */
++/* spec lists 0x20000 twice, I suspect they meant 0x10000 for one of them */
++#define IMAGE_SCN_MEM_PURGEABLE 0x00010000 /* reserved for "future" use */
++#define IMAGE_SCN_16BIT 0x00020000 /* reserved for "future" use */
++#define IMAGE_SCN_LOCKED 0x00040000 /* reserved for "future" use */
++#define IMAGE_SCN_PRELOAD 0x00080000 /* reserved for "future" use */
++/* and here they just stuck a 1-byte integer in the middle of a bitfield */
++#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 /* it does what it says on the box */
++#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
++#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
++#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
++#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
++#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
++#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
++#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
++#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
++#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000
++#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
++#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
++#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
++#define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000
++#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* extended relocations */
++#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */
++#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */
++#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* not pageable */
++#define IMAGE_SCN_MEM_SHARED 0x10000000 /* can be shared */
++#define IMAGE_SCN_MEM_EXECUTE 0x20000000 /* can be executed as code */
++#define IMAGE_SCN_MEM_READ 0x40000000 /* readable */
++#define IMAGE_SCN_MEM_WRITE 0x80000000 /* writeable */
++
++enum x64_coff_reloc_type {
++ IMAGE_REL_AMD64_ABSOLUTE = 0,
++ IMAGE_REL_AMD64_ADDR64,
++ IMAGE_REL_AMD64_ADDR32,
++ IMAGE_REL_AMD64_ADDR32N,
++ IMAGE_REL_AMD64_REL32,
++ IMAGE_REL_AMD64_REL32_1,
++ IMAGE_REL_AMD64_REL32_2,
++ IMAGE_REL_AMD64_REL32_3,
++ IMAGE_REL_AMD64_REL32_4,
++ IMAGE_REL_AMD64_REL32_5,
++ IMAGE_REL_AMD64_SECTION,
++ IMAGE_REL_AMD64_SECREL,
++ IMAGE_REL_AMD64_SECREL7,
++ IMAGE_REL_AMD64_TOKEN,
++ IMAGE_REL_AMD64_SREL32,
++ IMAGE_REL_AMD64_PAIR,
++ IMAGE_REL_AMD64_SSPAN32,
++};
++
++enum arm_coff_reloc_type {
++ IMAGE_REL_ARM_ABSOLUTE,
++ IMAGE_REL_ARM_ADDR32,
++ IMAGE_REL_ARM_ADDR32N,
++ IMAGE_REL_ARM_BRANCH2,
++ IMAGE_REL_ARM_BRANCH1,
++ IMAGE_REL_ARM_SECTION,
++ IMAGE_REL_ARM_SECREL,
++};
++
++enum sh_coff_reloc_type {
++ IMAGE_REL_SH3_ABSOLUTE,
++ IMAGE_REL_SH3_DIRECT16,
++ IMAGE_REL_SH3_DIRECT32,
++ IMAGE_REL_SH3_DIRECT8,
++ IMAGE_REL_SH3_DIRECT8_WORD,
++ IMAGE_REL_SH3_DIRECT8_LONG,
++ IMAGE_REL_SH3_DIRECT4,
++ IMAGE_REL_SH3_DIRECT4_WORD,
++ IMAGE_REL_SH3_DIRECT4_LONG,
++ IMAGE_REL_SH3_PCREL8_WORD,
++ IMAGE_REL_SH3_PCREL8_LONG,
++ IMAGE_REL_SH3_PCREL12_WORD,
++ IMAGE_REL_SH3_STARTOF_SECTION,
++ IMAGE_REL_SH3_SIZEOF_SECTION,
++ IMAGE_REL_SH3_SECTION,
++ IMAGE_REL_SH3_SECREL,
++ IMAGE_REL_SH3_DIRECT32_NB,
++ IMAGE_REL_SH3_GPREL4_LONG,
++ IMAGE_REL_SH3_TOKEN,
++ IMAGE_REL_SHM_PCRELPT,
++ IMAGE_REL_SHM_REFLO,
++ IMAGE_REL_SHM_REFHALF,
++ IMAGE_REL_SHM_RELLO,
++ IMAGE_REL_SHM_RELHALF,
++ IMAGE_REL_SHM_PAIR,
++ IMAGE_REL_SHM_NOMODE,
++};
++
++enum ppc_coff_reloc_type {
++ IMAGE_REL_PPC_ABSOLUTE,
++ IMAGE_REL_PPC_ADDR64,
++ IMAGE_REL_PPC_ADDR32,
++ IMAGE_REL_PPC_ADDR24,
++ IMAGE_REL_PPC_ADDR16,
++ IMAGE_REL_PPC_ADDR14,
++ IMAGE_REL_PPC_REL24,
++ IMAGE_REL_PPC_REL14,
++ IMAGE_REL_PPC_ADDR32N,
++ IMAGE_REL_PPC_SECREL,
++ IMAGE_REL_PPC_SECTION,
++ IMAGE_REL_PPC_SECREL16,
++ IMAGE_REL_PPC_REFHI,
++ IMAGE_REL_PPC_REFLO,
++ IMAGE_REL_PPC_PAIR,
++ IMAGE_REL_PPC_SECRELLO,
++ IMAGE_REL_PPC_GPREL,
++ IMAGE_REL_PPC_TOKEN,
++};
++
++enum x86_coff_reloc_type {
++ IMAGE_REL_I386_ABSOLUTE,
++ IMAGE_REL_I386_DIR16,
++ IMAGE_REL_I386_REL16,
++ IMAGE_REL_I386_DIR32,
++ IMAGE_REL_I386_DIR32NB,
++ IMAGE_REL_I386_SEG12,
++ IMAGE_REL_I386_SECTION,
++ IMAGE_REL_I386_SECREL,
++ IMAGE_REL_I386_TOKEN,
++ IMAGE_REL_I386_SECREL7,
++ IMAGE_REL_I386_REL32,
++};
++
++enum ia64_coff_reloc_type {
++ IMAGE_REL_IA64_ABSOLUTE,
++ IMAGE_REL_IA64_IMM14,
++ IMAGE_REL_IA64_IMM22,
++ IMAGE_REL_IA64_IMM64,
++ IMAGE_REL_IA64_DIR32,
++ IMAGE_REL_IA64_DIR64,
++ IMAGE_REL_IA64_PCREL21B,
++ IMAGE_REL_IA64_PCREL21M,
++ IMAGE_REL_IA64_PCREL21F,
++ IMAGE_REL_IA64_GPREL22,
++ IMAGE_REL_IA64_LTOFF22,
++ IMAGE_REL_IA64_SECTION,
++ IMAGE_REL_IA64_SECREL22,
++ IMAGE_REL_IA64_SECREL64I,
++ IMAGE_REL_IA64_SECREL32,
++ IMAGE_REL_IA64_DIR32NB,
++ IMAGE_REL_IA64_SREL14,
++ IMAGE_REL_IA64_SREL22,
++ IMAGE_REL_IA64_SREL32,
++ IMAGE_REL_IA64_UREL32,
++ IMAGE_REL_IA64_PCREL60X,
++ IMAGE_REL_IA64_PCREL60B,
++ IMAGE_REL_IA64_PCREL60F,
++ IMAGE_REL_IA64_PCREL60I,
++ IMAGE_REL_IA64_PCREL60M,
++ IMAGE_REL_IA64_IMMGPREL6,
++ IMAGE_REL_IA64_TOKEN,
++ IMAGE_REL_IA64_GPREL32,
++ IMAGE_REL_IA64_ADDEND,
++};
++
++struct coff_reloc {
++ uint32_t virtual_address;
++ uint32_t symbol_table_index;
++ union {
++ enum x64_coff_reloc_type x64_type;
++ enum arm_coff_reloc_type arm_type;
++ enum sh_coff_reloc_type sh_type;
++ enum ppc_coff_reloc_type ppc_type;
++ enum x86_coff_reloc_type x86_type;
++ enum ia64_coff_reloc_type ia64_type;
++ uint16_t data;
++ };
++};
++
++/*
++ * Definitions for the contents of the certs data block
++ */
++#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
++#define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0
++#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
++
++#define WIN_CERT_REVISION_1_0 0x0100
++#define WIN_CERT_REVISION_2_0 0x0200
++
++struct win_certificate {
++ uint32_t length;
++ uint16_t revision;
++ uint16_t cert_type;
++};
++
++#endif /* __LINUX_PE_H */
+--
+1.8.1.2
+
+
+From 658b2426b8704e4440d2d1614406be25385ffe0e Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:40 +0000
+Subject: [PATCH 21/46] pefile: Parse a PE binary to find a key and a signature
+ contained therein
+
+Parse a PE binary to find a key and a signature contained therein. Later
+patches will check the signature and add the key if the signature checks out.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/Kconfig | 10 +-
+ crypto/asymmetric_keys/Makefile | 8 ++
+ crypto/asymmetric_keys/pefile_parser.c | 185 +++++++++++++++++++++++++++++++++
+ crypto/asymmetric_keys/pefile_parser.h | 31 ++++++
+ 4 files changed, 233 insertions(+), 1 deletion(-)
+ create mode 100644 crypto/asymmetric_keys/pefile_parser.c
+ create mode 100644 crypto/asymmetric_keys/pefile_parser.h
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index 413f3f6..2e7315c 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -31,7 +31,7 @@ config X509_CERTIFICATE_PARSER
+ select ASN1
+ select OID_REGISTRY
+ help
+- This option procides support for parsing X.509 format blobs for key
++ This option provides support for parsing X.509 format blobs for key
+ data and provides the ability to instantiate a crypto key from a
+ public key packet found inside the certificate.
+
+@@ -44,4 +44,12 @@ config PKCS7_MESSAGE_PARSER
+ This option provides support for parsing PKCS#7 format messages for
+ signature data and provides the ability to verify the signature.
+
++config PE_FILE_PARSER
++ tristate "PE binary-wrapped key parser"
++ depends on X509_CERTIFICATE_PARSER
++ depends on PKCS7_MESSAGE_PARSER
++ help
++ This option provides support for parsing signed PE binaries that
++ contain an X.509 certificate in an internal section.
++
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index d63cb43..2675146 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -40,3 +40,11 @@ $(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
+ $(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h
+
+ clean-files += pkcs7-asn1.c pkcs7-asn1.h
++
++#
++# Signed PE binary-wrapped key handling
++#
++obj-$(CONFIG_PE_FILE_PARSER) += pefile_key_parser.o
++
++pefile_key_parser-y := \
++ pefile_parser.o
+diff --git a/crypto/asymmetric_keys/pefile_parser.c b/crypto/asymmetric_keys/pefile_parser.c
+new file mode 100644
+index 0000000..fb80cf0
+--- /dev/null
++++ b/crypto/asymmetric_keys/pefile_parser.c
+@@ -0,0 +1,185 @@
++/* Parse a signed PE binary that wraps a key.
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "PEFILE: "fmt
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/pe.h>
++#include <keys/asymmetric-subtype.h>
++#include <keys/asymmetric-parser.h>
++#include <crypto/hash.h>
++#include "asymmetric_keys.h"
++#include "public_key.h"
++#include "pefile_parser.h"
++
++/*
++ * Parse a PE binary.
++ */
++static int pefile_parse_binary(struct key_preparsed_payload *prep,
++ struct pefile_context *ctx)
++{
++ const struct mz_hdr *mz = prep->data;
++ const struct pe_hdr *pe;
++ const struct pe32_opt_hdr *pe32;
++ const struct pe32plus_opt_hdr *pe64;
++ const struct data_directory *ddir;
++ const struct data_dirent *dde;
++ const struct section_header *secs, *sec;
++ unsigned loop;
++ size_t cursor, datalen = prep->datalen;
++
++ kenter("");
++
++#define chkaddr(base, x, s) \
++ do { \
++ if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
++ return -ELIBBAD; \
++ } while(0)
++
++ chkaddr(0, 0, sizeof(*mz));
++ if (mz->magic != MZ_MAGIC)
++ return -ELIBBAD;
++ cursor = sizeof(*mz);
++
++ chkaddr(cursor, mz->peaddr, sizeof(*pe));
++ pe = prep->data + mz->peaddr;
++ if (pe->magic != PE_MAGIC)
++ return -ELIBBAD;
++ cursor = mz->peaddr + sizeof(*pe);
++
++ chkaddr(0, cursor, sizeof(pe32->magic));
++ pe32 = prep->data + cursor;
++ pe64 = prep->data + cursor;
++
++ switch (pe32->magic) {
++ case PE_OPT_MAGIC_PE32:
++ chkaddr(0, cursor, sizeof(*pe32));
++ ctx->image_checksum_offset =
++ (unsigned long)&pe32->csum - (unsigned long)prep->data;
++ ctx->header_size = pe32->header_size;
++ cursor += sizeof(*pe32);
++ ctx->n_data_dirents = pe32->data_dirs;
++ break;
++
++ case PE_OPT_MAGIC_PE32PLUS:
++ chkaddr(0, cursor, sizeof(*pe64));
++ ctx->image_checksum_offset =
++ (unsigned long)&pe64->csum - (unsigned long)prep->data;
++ ctx->header_size = pe64->header_size;
++ cursor += sizeof(*pe64);
++ ctx->n_data_dirents = pe64->data_dirs;
++ break;
++
++ default:
++ pr_devel("Unknown PEOPT magic = %04hx\n", pe32->magic);
++ return -ELIBBAD;
++ }
++
++ pr_devel("checksum @ %x\n", ctx->image_checksum_offset);
++ pr_devel("header size = %x\n", ctx->header_size);
++
++ if (cursor >= ctx->header_size || ctx->header_size >= datalen)
++ return -ELIBBAD;
++
++ if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde) ||
++ ctx->n_data_dirents < sizeof(*ddir) / sizeof(*dde))
++ return -ELIBBAD;
++
++ ddir = prep->data + cursor;
++ cursor += sizeof(*dde) * ctx->n_data_dirents;
++
++ ctx->cert_dirent_offset =
++ (unsigned long)&ddir->certs - (unsigned long)prep->data;
++ ctx->certs_size = ddir->certs.size;
++
++ if (!ddir->certs.virtual_address || !ddir->certs.size) {
++ pr_devel("Unsigned PE binary\n");
++ return -EKEYREJECTED;
++ }
++
++ chkaddr(ctx->header_size, ddir->certs.virtual_address, ddir->certs.size);
++ ctx->sig_offset = ddir->certs.virtual_address;
++ ctx->sig_len = ddir->certs.size;
++ pr_devel("cert = %x @%x [%*ph]\n",
++ ctx->sig_len, ctx->sig_offset,
++ ctx->sig_len, prep->data + ctx->sig_offset);
++
++ /* Parse the section table, checking the parameters and looking for the
++ * section containing the list of keys.
++ */
++ ctx->n_sections = pe->sections;
++ if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
++ return -ELIBBAD;
++ ctx->secs = secs = prep->data + cursor;
++ cursor += sizeof(*sec) * ctx->n_sections;
++
++ for (loop = 0; loop < ctx->n_sections; loop++) {
++ sec = &secs[loop];
++ chkaddr(cursor, sec->data_addr, sec->raw_data_size);
++ if (memcmp(sec->name, ".keylist", 8) == 0) {
++ ctx->keylist_offset = sec->data_addr;
++ ctx->keylist_len = sec->raw_data_size;
++ }
++ }
++
++ if (ctx->keylist_offset == 0) {
++ pr_devel("No .keylist section in PE binary\n");
++ return -ENOENT;
++ }
++
++ pr_devel("keylist = %x @%x [%*ph]\n",
++ ctx->keylist_len, ctx->keylist_offset,
++ ctx->keylist_len, prep->data + ctx->keylist_offset);
++
++ return 0;
++}
++
++/*
++ * Parse a PE binary.
++ */
++static int pefile_key_preparse(struct key_preparsed_payload *prep)
++{
++ struct pefile_context ctx;
++ int ret;
++
++ kenter("");
++
++ memset(&ctx, 0, sizeof(ctx));
++ ret = pefile_parse_binary(prep, &ctx);
++ if (ret < 0)
++ return ret;
++
++ return -ENOANO; // Not yet complete
++}
++
++static struct asymmetric_key_parser pefile_key_parser = {
++ .owner = THIS_MODULE,
++ .name = "pefile",
++ .parse = pefile_key_preparse,
++};
++
++/*
++ * Module stuff
++ */
++static int __init pefile_key_init(void)
++{
++ return register_asymmetric_key_parser(&pefile_key_parser);
++}
++
++static void __exit pefile_key_exit(void)
++{
++ unregister_asymmetric_key_parser(&pefile_key_parser);
++}
++
++module_init(pefile_key_init);
++module_exit(pefile_key_exit);
+diff --git a/crypto/asymmetric_keys/pefile_parser.h b/crypto/asymmetric_keys/pefile_parser.h
+new file mode 100644
+index 0000000..82bcaf6
+--- /dev/null
++++ b/crypto/asymmetric_keys/pefile_parser.h
+@@ -0,0 +1,31 @@
++/* PE Binary parser bits
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++#include "pkcs7_parser.h"
++
++struct pefile_context {
++ unsigned header_size;
++ unsigned image_checksum_offset;
++ unsigned cert_dirent_offset;
++ unsigned n_data_dirents;
++ unsigned n_sections;
++ unsigned certs_size;
++ unsigned sig_offset;
++ unsigned sig_len;
++ unsigned keylist_offset;
++ unsigned keylist_len;
++ const struct section_header *secs;
++ struct pkcs7_message *pkcs7;
++
++ /* PKCS#7 MS Individual Code Signing content */
++ const void *digest; /* Digest */
++ unsigned digest_len; /* Digest length */
++ enum pkey_hash_algo digest_algo; /* Digest algorithm */
++};
+--
+1.8.1.2
+
+
+From 0405dbbba60584930e238a98e0de48b70141e5ba Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:40 +0000
+Subject: [PATCH 22/46] pefile: Strip the wrapper off of the cert data block
+
+The certificate data block in a PE binary has a wrapper around the PKCS#7
+signature we actually want to get at. Strip this off and check that we've got
+something that appears to be a PKCS#7 signature.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/pefile_parser.c | 60 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 60 insertions(+)
+
+diff --git a/crypto/asymmetric_keys/pefile_parser.c b/crypto/asymmetric_keys/pefile_parser.c
+index fb80cf0..f2d4df0 100644
+--- a/crypto/asymmetric_keys/pefile_parser.c
++++ b/crypto/asymmetric_keys/pefile_parser.c
+@@ -15,6 +15,7 @@
+ #include <linux/slab.h>
+ #include <linux/err.h>
+ #include <linux/pe.h>
++#include <linux/asn1.h>
+ #include <keys/asymmetric-subtype.h>
+ #include <keys/asymmetric-parser.h>
+ #include <crypto/hash.h>
+@@ -145,6 +146,61 @@ static int pefile_parse_binary(struct key_preparsed_payload *prep,
+ }
+
+ /*
++ * Check and strip the PE wrapper from around the signature and check that the
++ * remnant looks something like PKCS#7.
++ */
++static int pefile_strip_sig_wrapper(struct key_preparsed_payload *prep,
++ struct pefile_context *ctx)
++{
++ struct win_certificate wrapper;
++ const u8 *pkcs7;
++
++ if (ctx->sig_len < sizeof(wrapper)) {
++ pr_devel("Signature wrapper too short\n");
++ return -ELIBBAD;
++ }
++
++ memcpy(&wrapper, prep->data + ctx->sig_offset, sizeof(wrapper));
++ pr_devel("sig wrapper = { %x, %x, %x }\n",
++ wrapper.length, wrapper.revision, wrapper.cert_type);
++ if (wrapper.length != ctx->sig_len) {
++ pr_devel("Signature wrapper len wrong\n");
++ return -ELIBBAD;
++ }
++ if (wrapper.revision != WIN_CERT_REVISION_2_0) {
++ pr_devel("Signature is not revision 2.0\n");
++ return -ENOTSUPP;
++ }
++ if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
++ pr_devel("Signature certificate type is not PKCS\n");
++ return -ENOTSUPP;
++ }
++
++ ctx->sig_offset += sizeof(wrapper);
++ ctx->sig_len -= sizeof(wrapper);
++ if (ctx->sig_len == 0) {
++ pr_devel("Signature data missing\n");
++ return -EKEYREJECTED;
++ }
++
++ /* What's left should a PKCS#7 cert */
++ pkcs7 = prep->data + ctx->sig_offset;
++ if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) {
++ if (pkcs7[1] == 0x82 &&
++ pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) &&
++ pkcs7[3] == ((ctx->sig_len - 4) & 0xff))
++ return 0;
++ if (pkcs7[1] == 0x80)
++ return 0;
++ if (pkcs7[1] > 0x82)
++ return -EMSGSIZE;
++ }
++
++ pr_devel("Signature data not PKCS#7\n");
++ return -ELIBBAD;
++}
++
++/*
+ * Parse a PE binary.
+ */
+ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+@@ -159,6 +215,10 @@ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+ if (ret < 0)
+ return ret;
+
++ ret = pefile_strip_sig_wrapper(prep, &ctx);
++ if (ret < 0)
++ return ret;
++
+ return -ENOANO; // Not yet complete
+ }
+
+--
+1.8.1.2
+
+
+From 6c5d86f5c8be7c3357c143ab1b2fba9ebc5bf16e Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:40 +0000
+Subject: [PATCH 23/46] pefile: Parse the presumed PKCS#7 content of the
+ certificate blob
+
+Parse the content of the certificate blob, presuming it to be PKCS#7 format.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/pefile_parser.c | 18 +++++++++++++++++-
+ 1 file changed, 17 insertions(+), 1 deletion(-)
+
+diff --git a/crypto/asymmetric_keys/pefile_parser.c b/crypto/asymmetric_keys/pefile_parser.c
+index f2d4df0..056500f 100644
+--- a/crypto/asymmetric_keys/pefile_parser.c
++++ b/crypto/asymmetric_keys/pefile_parser.c
+@@ -205,6 +205,7 @@ static int pefile_strip_sig_wrapper(struct key_preparsed_payload *prep,
+ */
+ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+ {
++ struct pkcs7_message *pkcs7;
+ struct pefile_context ctx;
+ int ret;
+
+@@ -219,7 +220,22 @@ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+ if (ret < 0)
+ return ret;
+
+- return -ENOANO; // Not yet complete
++ pkcs7 = pkcs7_parse_message(prep->data + ctx.sig_offset, ctx.sig_len);
++ if (IS_ERR(pkcs7))
++ return PTR_ERR(pkcs7);
++ ctx.pkcs7 = pkcs7;
++
++ if (!ctx.pkcs7->data || !ctx.pkcs7->data_len) {
++ pr_devel("PKCS#7 message does not contain data\n");
++ ret = -EBADMSG;
++ goto error;
++ }
++
++ ret = -ENOANO; // Not yet complete
++
++error:
++ pkcs7_free_message(ctx.pkcs7);
++ return ret;
+ }
+
+ static struct asymmetric_key_parser pefile_key_parser = {
+--
+1.8.1.2
+
+
+From 73a990445ce2d4ad35dca7b67ac3fbf280a9dafa Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:41 +0000
+Subject: [PATCH 24/46] pefile: Parse the "Microsoft individual code signing"
+ data blob
+
+The PKCS#7 certificate should contain a "Microsoft individual code signing"
+data blob as its signed content. This blob contains a digest of the signed
+content of the PE binary and the OID of the digest algorithm used (typically
+SHA256).
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/Makefile | 9 ++-
+ crypto/asymmetric_keys/mscode.asn1 | 28 +++++++++
+ crypto/asymmetric_keys/mscode_parser.c | 110 +++++++++++++++++++++++++++++++++
+ crypto/asymmetric_keys/pefile_parser.c | 6 ++
+ crypto/asymmetric_keys/pefile_parser.h | 5 ++
+ include/linux/oid_registry.h | 6 +-
+ 6 files changed, 162 insertions(+), 2 deletions(-)
+ create mode 100644 crypto/asymmetric_keys/mscode.asn1
+ create mode 100644 crypto/asymmetric_keys/mscode_parser.c
+
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index 2675146..ddc64bb 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -47,4 +47,11 @@ clean-files += pkcs7-asn1.c pkcs7-asn1.h
+ obj-$(CONFIG_PE_FILE_PARSER) += pefile_key_parser.o
+
+ pefile_key_parser-y := \
+- pefile_parser.o
++ pefile_parser.o \
++ mscode_parser.o \
++ mscode-asn1.o
++
++$(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h
++$(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h
++
++clean-files += mscode-asn1.c mscode-asn1.h
+diff --git a/crypto/asymmetric_keys/mscode.asn1 b/crypto/asymmetric_keys/mscode.asn1
+new file mode 100644
+index 0000000..6d09ba4
+--- /dev/null
++++ b/crypto/asymmetric_keys/mscode.asn1
+@@ -0,0 +1,28 @@
++--- Microsoft individual code signing data blob parser
++---
++--- Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++--- Written by David Howells (dhowells@redhat.com)
++---
++--- This program is free software; you can redistribute it and/or
++--- modify it under the terms of the GNU General Public Licence
++--- as published by the Free Software Foundation; either version
++--- 2 of the Licence, or (at your option) any later version.
++---
++
++MSCode ::= SEQUENCE {
++ type SEQUENCE {
++ contentType ContentType,
++ parameters ANY
++ },
++ content SEQUENCE {
++ digestAlgorithm DigestAlgorithmIdentifier,
++ digest OCTET STRING ({ mscode_note_digest })
++ }
++}
++
++ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type })
++
++DigestAlgorithmIdentifier ::= SEQUENCE {
++ algorithm OBJECT IDENTIFIER ({ mscode_note_digest_algo }),
++ parameters ANY OPTIONAL
++}
+diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c
+new file mode 100644
+index 0000000..0bd68e0
+--- /dev/null
++++ b/crypto/asymmetric_keys/mscode_parser.c
+@@ -0,0 +1,110 @@
++/* Parse a Microsoft Individual Code Signing blob
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "MSCODE: "fmt
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++#include <linux/oid_registry.h>
++#include "pefile_parser.h"
++#include "mscode-asn1.h"
++
++/*
++ * Parse a Microsoft Individual Code Signing blob
++ */
++int mscode_parse(struct pefile_context *ctx)
++{
++ pr_devel("Data: %zu [%*ph]\n",
++ ctx->pkcs7->data_len + ctx->pkcs7->data_hdrlen,
++ (unsigned)(ctx->pkcs7->data_len + ctx->pkcs7->data_hdrlen),
++ ctx->pkcs7->data - ctx->pkcs7->data_hdrlen);
++
++ return asn1_ber_decoder(&mscode_decoder, ctx,
++ ctx->pkcs7->data - ctx->pkcs7->data_hdrlen,
++ ctx->pkcs7->data_len + ctx->pkcs7->data_hdrlen);
++}
++
++/*
++ * Check the content type OID
++ */
++int mscode_note_content_type(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ enum OID oid;
++
++ oid = look_up_OID(value, vlen);
++ if (oid == OID__NR) {
++ char buffer[50];
++ sprint_oid(value, vlen, buffer, sizeof(buffer));
++ printk("MSCODE: Unknown OID: %s\n", buffer);
++ return -EBADMSG;
++ }
++
++ if (oid != OID_msIndividualSPKeyPurpose) {
++ printk("MSCODE: Unexpected content type OID %u\n", oid);
++ return -EBADMSG;
++ }
++
++ return 0;
++}
++
++/*
++ * Note the digest algorithm OID
++ */
++int mscode_note_digest_algo(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pefile_context *ctx = context;
++ char buffer[50];
++ enum OID oid;
++
++ oid = look_up_OID(value, vlen);
++ switch (oid) {
++ case OID_md4:
++ ctx->digest_algo = PKEY_HASH_MD4;
++ break;
++ case OID_md5:
++ ctx->digest_algo = PKEY_HASH_MD5;
++ break;
++ case OID_sha1:
++ ctx->digest_algo = PKEY_HASH_SHA1;
++ break;
++ case OID_sha256:
++ ctx->digest_algo = PKEY_HASH_SHA256;
++ break;
++
++ case OID__NR:
++ sprint_oid(value, vlen, buffer, sizeof(buffer));
++ printk("MSCODE: Unknown OID: %s\n", buffer);
++ return -EBADMSG;
++
++ default:
++ printk("MSCODE: Unsupported content type: %u\n", oid);
++ return -ENOPKG;
++ }
++
++ return 0;
++}
++
++/*
++ * Note the digest we're guaranteeing with this certificate
++ */
++int mscode_note_digest(void *context, size_t hdrlen,
++ unsigned char tag,
++ const void *value, size_t vlen)
++{
++ struct pefile_context *ctx = context;
++ ctx->digest = value;
++ ctx->digest_len = vlen;
++ return 0;
++}
+diff --git a/crypto/asymmetric_keys/pefile_parser.c b/crypto/asymmetric_keys/pefile_parser.c
+index 056500f..f1c8cc1 100644
+--- a/crypto/asymmetric_keys/pefile_parser.c
++++ b/crypto/asymmetric_keys/pefile_parser.c
+@@ -231,6 +231,12 @@ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+ goto error;
+ }
+
++ ret = mscode_parse(&ctx);
++ if (ret < 0)
++ goto error;
++
++ pr_devel("Digest: %u [%*ph]\n", ctx.digest_len, ctx.digest_len, ctx.digest);
++
+ ret = -ENOANO; // Not yet complete
+
+ error:
+diff --git a/crypto/asymmetric_keys/pefile_parser.h b/crypto/asymmetric_keys/pefile_parser.h
+index 82bcaf6..c3462b7 100644
+--- a/crypto/asymmetric_keys/pefile_parser.h
++++ b/crypto/asymmetric_keys/pefile_parser.h
+@@ -29,3 +29,8 @@ struct pefile_context {
+ unsigned digest_len; /* Digest length */
+ enum pkey_hash_algo digest_algo; /* Digest algorithm */
+ };
++
++/*
++ * mscode_parser.c
++ */
++extern int mscode_parse(struct pefile_context *ctx);
+diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
+index edeff85..332dcf5 100644
+--- a/include/linux/oid_registry.h
++++ b/include/linux/oid_registry.h
+@@ -52,8 +52,12 @@ enum OID {
+ OID_md4, /* 1.2.840.113549.2.4 */
+ OID_md5, /* 1.2.840.113549.2.5 */
+
+- OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
++ /* Microsoft Authenticode & Software Publishing */
++ OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
++ OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */
+ OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
++
++ OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
+ OID_sha1, /* 1.3.14.3.2.26 */
+ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
+
+--
+1.8.1.2
+
+
+From e969b6b286982975f056d8eb5d951be992a4ff96 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:41 +0000
+Subject: [PATCH 25/46] pefile: Digest the PE binary and compare to the PKCS#7
+ data
+
+Digest the signed parts of the PE binary, canonicalising the section table
+before we need it, and then compare the the resulting digest to the one in the
+PKCS#7 signed content.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/pefile_parser.c | 198 +++++++++++++++++++++++++++++++++
+ 1 file changed, 198 insertions(+)
+
+diff --git a/crypto/asymmetric_keys/pefile_parser.c b/crypto/asymmetric_keys/pefile_parser.c
+index f1c8cc1..dfdb85e 100644
+--- a/crypto/asymmetric_keys/pefile_parser.c
++++ b/crypto/asymmetric_keys/pefile_parser.c
+@@ -201,6 +201,193 @@ static int pefile_strip_sig_wrapper(struct key_preparsed_payload *prep,
+ }
+
+ /*
++ * Compare two sections for canonicalisation.
++ */
++static int pefile_compare_shdrs(const void *a, const void *b)
++{
++ const struct section_header *shdra = a;
++ const struct section_header *shdrb = b;
++ int rc;
++
++ if (shdra->data_addr > shdrb->data_addr)
++ return 1;
++ if (shdrb->data_addr > shdra->data_addr)
++ return -1;
++
++ if (shdra->virtual_address > shdrb->virtual_address)
++ return 1;
++ if (shdrb->virtual_address > shdra->virtual_address)
++ return -1;
++
++ rc = strcmp(shdra->name, shdrb->name);
++ if (rc != 0)
++ return rc;
++
++ if (shdra->virtual_size > shdrb->virtual_size)
++ return 1;
++ if (shdrb->virtual_size > shdra->virtual_size)
++ return -1;
++
++ if (shdra->raw_data_size > shdrb->raw_data_size)
++ return 1;
++ if (shdrb->raw_data_size > shdra->raw_data_size)
++ return -1;
++
++ return 0;
++}
++
++/*
++ * Load the contents of the PE binary into the digest, leaving out the image
++ * checksum and the certificate data block.
++ */
++static int pefile_digest_pe_contents(struct key_preparsed_payload *prep,
++ struct pefile_context *ctx,
++ struct shash_desc *desc)
++{
++ unsigned *canon, tmp, loop, i, hashed_bytes;
++ int ret;
++
++ /* Digest the header and data directory, but leave out the image
++ * checksum and the data dirent for the signature.
++ */
++ ret = crypto_shash_update(desc, prep->data, ctx->image_checksum_offset);
++ if (ret < 0)
++ return ret;
++
++ tmp = ctx->image_checksum_offset + sizeof(uint32_t);
++ ret = crypto_shash_update(desc, prep->data + tmp,
++ ctx->cert_dirent_offset - tmp);
++ if (ret < 0)
++ return ret;
++
++ tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
++ ret = crypto_shash_update(desc, prep->data + tmp,
++ ctx->header_size - tmp);
++ if (ret < 0)
++ return ret;
++
++ canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
++ if (!canon)
++ return -ENOMEM;
++
++ /* We have to canonicalise the section table, so we perform an
++ * insertion sort.
++ */
++ canon[0] = 0;
++ for (loop = 1; loop < ctx->n_sections; loop++) {
++ for (i = 0; i < loop; i++) {
++ if (pefile_compare_shdrs(&ctx->secs[canon[i]],
++ &ctx->secs[loop]) > 0) {
++ memmove(&canon[i + 1], &canon[i],
++ (loop - i) * sizeof(canon[0]));
++ break;
++ }
++ }
++ canon[i] = loop;
++ }
++
++ hashed_bytes = ctx->header_size;
++ for (loop = 0; loop < ctx->n_sections; loop++) {
++ i = canon[loop];
++ if (ctx->secs[i].raw_data_size == 0)
++ continue;
++ ret = crypto_shash_update(desc,
++ prep->data + ctx->secs[i].data_addr,
++ ctx->secs[i].raw_data_size);
++ if (ret < 0) {
++ kfree(canon);
++ return ret;
++ }
++ hashed_bytes += ctx->secs[i].raw_data_size;
++ }
++ kfree(canon);
++
++ if (prep->datalen > hashed_bytes) {
++ tmp = hashed_bytes + ctx->certs_size;
++ ret = crypto_shash_update(desc,
++ prep->data + hashed_bytes,
++ prep->datalen - tmp);
++ if (ret < 0)
++ return ret;
++ }
++
++ return 0;
++}
++
++/*
++ * Digest the contents of the PE binary, leaving out the image checksum and the
++ * certificate data block.
++ */
++static int pefile_digest_pe(struct key_preparsed_payload *prep,
++ struct pefile_context *ctx)
++{
++ struct crypto_shash *tfm;
++ struct shash_desc *desc;
++ size_t digest_size, desc_size;
++ void *digest;
++ int ret;
++
++ kenter(",%u", ctx->digest_algo);
++
++ /* Allocate the hashing algorithm we're going to need and find out how
++ * big the hash operational data will be.
++ */
++ tfm = crypto_alloc_shash(pkey_hash_algo_name[ctx->digest_algo], 0, 0);
++ if (IS_ERR(tfm))
++ return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
++
++ desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
++ digest_size = crypto_shash_digestsize(tfm);
++
++ if (digest_size != ctx->digest_len) {
++ pr_debug("Digest size mismatch (%zx != %x)\n",
++ digest_size, ctx->digest_len);
++ ret = -EBADMSG;
++ goto error_no_desc;
++ }
++ pr_devel("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
++
++ ret = -ENOMEM;
++ desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
++ if (!desc)
++ goto error_no_desc;
++
++ desc->tfm = tfm;
++ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
++ ret = crypto_shash_init(desc);
++ if (ret < 0)
++ goto error;
++
++ ret = pefile_digest_pe_contents(prep, ctx, desc);
++ if (ret < 0)
++ goto error;
++
++ digest = (void *)desc + desc_size;
++ ret = crypto_shash_final(desc, digest);
++ if (ret < 0)
++ goto error;
++
++ pr_devel("Digest calc = [%*ph]\n", ctx->digest_len, digest);
++
++ /* Check that the PE file digest matches that in the MSCODE part of the
++ * PKCS#7 certificate.
++ */
++ if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
++ pr_debug("Digest mismatch\n");
++ ret = -EKEYREJECTED;
++ } else {
++ pr_debug("The digests match!\n");
++ }
++
++error:
++ kfree(desc);
++error_no_desc:
++ crypto_free_shash(tfm);
++ kleave(" = %d", ret);
++ return ret;
++}
++
++/*
+ * Parse a PE binary.
+ */
+ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+@@ -237,6 +424,17 @@ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+
+ pr_devel("Digest: %u [%*ph]\n", ctx.digest_len, ctx.digest_len, ctx.digest);
+
++ /* Generate the digest and check against the PKCS7 certificate
++ * contents.
++ */
++ ret = pefile_digest_pe(prep, &ctx);
++ if (ret < 0)
++ goto error;
++
++ ret = pkcs7_verify(pkcs7);
++ if (ret < 0)
++ goto error;
++
+ ret = -ENOANO; // Not yet complete
+
+ error:
+--
+1.8.1.2
+
+
+From 860c4eb4665073836356c04b13a09464c56a7f7c Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 18 Jan 2013 13:58:35 +0000
+Subject: [PATCH 26/46] PEFILE: Validate PKCS#7 trust chain
+
+Validate the PKCS#7 trust chain against the contents of the system keyring.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ crypto/asymmetric_keys/Kconfig | 1 +
+ crypto/asymmetric_keys/pefile_parser.c | 5 +++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index 2e7315c..2777916 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -48,6 +48,7 @@ config PE_FILE_PARSER
+ tristate "PE binary-wrapped key parser"
+ depends on X509_CERTIFICATE_PARSER
+ depends on PKCS7_MESSAGE_PARSER
++ depends on SYSTEM_TRUSTED_KEYRING
+ help
+ This option provides support for parsing signed PE binaries that
+ contain an X.509 certificate in an internal section.
+diff --git a/crypto/asymmetric_keys/pefile_parser.c b/crypto/asymmetric_keys/pefile_parser.c
+index dfdb85e..edad948 100644
+--- a/crypto/asymmetric_keys/pefile_parser.c
++++ b/crypto/asymmetric_keys/pefile_parser.c
+@@ -18,6 +18,7 @@
+ #include <linux/asn1.h>
+ #include <keys/asymmetric-subtype.h>
+ #include <keys/asymmetric-parser.h>
++#include <keys/system_keyring.h>
+ #include <crypto/hash.h>
+ #include "asymmetric_keys.h"
+ #include "public_key.h"
+@@ -435,6 +436,10 @@ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+ if (ret < 0)
+ goto error;
+
++ ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &prep->trusted);
++ if (ret < 0)
++ goto error;
++
+ ret = -ENOANO; // Not yet complete
+
+ error:
+--
+1.8.1.2
+
+
+From 8fe70d2f6b5c7119629d984d63ffa2ea6f86e3ec Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Tue, 15 Jan 2013 15:33:42 +0000
+Subject: [PATCH 27/46] PEFILE: Load the contained key if we consider the
+ container to be validly signed
+
+Load the key contained in the PE binary if the signature on the container can
+be verified by following the chain of X.509 certificates in the PKCS#7 message
+to a key that we already trust. Typically, the trusted key will be acquired
+from a source outside of the kernel, such as the UEFI database.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+Reviewed-by: Kees Cook <keescook@chromium.org>
+---
+ crypto/asymmetric_keys/pefile_parser.c | 11 ++++++++++-
+ crypto/asymmetric_keys/x509_parser.h | 3 +++
+ crypto/asymmetric_keys/x509_public_key.c | 3 ++-
+ 3 files changed, 15 insertions(+), 2 deletions(-)
+
+diff --git a/crypto/asymmetric_keys/pefile_parser.c b/crypto/asymmetric_keys/pefile_parser.c
+index edad948..c3efe39 100644
+--- a/crypto/asymmetric_keys/pefile_parser.c
++++ b/crypto/asymmetric_keys/pefile_parser.c
+@@ -395,6 +395,8 @@ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+ {
+ struct pkcs7_message *pkcs7;
+ struct pefile_context ctx;
++ const void *saved_data;
++ size_t saved_datalen;
+ int ret;
+
+ kenter("");
+@@ -440,7 +442,14 @@ static int pefile_key_preparse(struct key_preparsed_payload *prep)
+ if (ret < 0)
+ goto error;
+
+- ret = -ENOANO; // Not yet complete
++ /* We can now try to load the key */
++ saved_data = prep->data;
++ saved_datalen = prep->datalen;
++ prep->data += ctx.keylist_offset;
++ prep->datalen = ctx.keylist_len;
++ ret = x509_key_preparse(prep);
++ prep->data = saved_data;
++ prep->datalen = saved_datalen;
+
+ error:
+ pkcs7_free_message(ctx.pkcs7);
+diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
+index 5e35fba..65452c4 100644
+--- a/crypto/asymmetric_keys/x509_parser.h
++++ b/crypto/asymmetric_keys/x509_parser.h
+@@ -12,6 +12,8 @@
+ #include <linux/time.h>
+ #include <crypto/public_key.h>
+
++struct key_preparsed_payload;
++
+ struct x509_certificate {
+ struct x509_certificate *next;
+ const struct x509_certificate *signer; /* Certificate that signed this one */
+@@ -47,3 +49,4 @@ extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen
+ extern int x509_get_sig_params(struct x509_certificate *cert);
+ extern int x509_check_signature(const struct public_key *pub,
+ struct x509_certificate *cert);
++extern int x509_key_preparse(struct key_preparsed_payload *prep);
+diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
+index 0f55e3b..c3e5a6d 100644
+--- a/crypto/asymmetric_keys/x509_public_key.c
++++ b/crypto/asymmetric_keys/x509_public_key.c
+@@ -105,7 +105,7 @@ EXPORT_SYMBOL_GPL(x509_check_signature);
+ /*
+ * Attempt to parse a data blob for a key as an X509 certificate.
+ */
+-static int x509_key_preparse(struct key_preparsed_payload *prep)
++int x509_key_preparse(struct key_preparsed_payload *prep)
+ {
+ struct x509_certificate *cert;
+ struct tm now;
+@@ -229,6 +229,7 @@ error_free_cert:
+ x509_free_certificate(cert);
+ return ret;
+ }
++EXPORT_SYMBOL_GPL(x509_key_preparse);
+
+ static struct asymmetric_key_parser x509_key_parser = {
+ .owner = THIS_MODULE,
+--
+1.8.1.2
+
+
+From 9bd76edb23767533d299459f595c7b3730c320a5 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Thu, 20 Sep 2012 10:40:56 -0400
+Subject: [PATCH 28/46] Secure boot: Add new capability
+
+Secure boot adds certain policy requirements, including that root must not
+be able to do anything that could cause the kernel to execute arbitrary code.
+The simplest way to handle this would seem to be to add a new capability
+and gate various functionality on that. We'll then strip it from the initial
+capability set if required.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+---
+ include/uapi/linux/capability.h | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
+index ba478fa..7109e65 100644
+--- a/include/uapi/linux/capability.h
++++ b/include/uapi/linux/capability.h
+@@ -343,7 +343,11 @@ struct vfs_cap_data {
+
+ #define CAP_BLOCK_SUSPEND 36
+
+-#define CAP_LAST_CAP CAP_BLOCK_SUSPEND
++/* Allow things that trivially permit root to modify the running kernel */
++
++#define CAP_COMPROMISE_KERNEL 37
++
++#define CAP_LAST_CAP CAP_COMPROMISE_KERNEL
+
+ #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+
+--
+1.8.1.2
+
+
+From af74a1cc301f6042cd8d972d2b2b713592c547e6 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Thu, 20 Sep 2012 10:41:05 -0400
+Subject: [PATCH 29/46] SELinux: define mapping for new Secure Boot capability
+
+Add the name of the new Secure Boot capability. This allows SELinux
+policies to properly map CAP_COMPROMISE_KERNEL to the appropriate
+capability class.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ security/selinux/include/classmap.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
+index 14d04e6..ed99a2d 100644
+--- a/security/selinux/include/classmap.h
++++ b/security/selinux/include/classmap.h
+@@ -146,8 +146,8 @@ struct security_class_mapping secclass_map[] = {
+ { "memprotect", { "mmap_zero", NULL } },
+ { "peer", { "recv", NULL } },
+ { "capability2",
+- { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend",
+- NULL } },
++ { "mac_override", "mac_admin", "syslog", "wake_alarm",
++ "block_suspend", "compromise_kernel", NULL } },
+ { "kernel_service", { "use_as_override", "create_files_as", NULL } },
+ { "tun_socket",
+ { COMMON_SOCK_PERMS, "attach_queue", NULL } },
+--
+1.8.1.2
+
+
+From be17631af0e3aa91cdee269ba065271a08ad2352 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Thu, 20 Sep 2012 10:41:02 -0400
+Subject: [PATCH 30/46] Secure boot: Add a dummy kernel parameter that will
+ switch on Secure Boot mode
+
+This forcibly drops CAP_COMPROMISE_KERNEL from both cap_permitted and cap_bset
+in the init_cred struct, which everything else inherits from. This works on
+any machine and can be used to develop even if the box doesn't have UEFI.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ Documentation/kernel-parameters.txt | 7 +++++++
+ kernel/cred.c | 17 +++++++++++++++++
+ 2 files changed, 24 insertions(+)
+
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 6c72381..7dffdd5 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -2654,6 +2654,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
+ Note: increases power consumption, thus should only be
+ enabled if running jitter sensitive (HPC/RT) workloads.
+
++ secureboot_enable=
++ [KNL] Enables an emulated UEFI Secure Boot mode. This
++ locks down various aspects of the kernel guarded by the
++ CAP_COMPROMISE_KERNEL capability. This includes things
++ like /dev/mem, IO port access, and other areas. It can
++ be used on non-UEFI machines for testing purposes.
++
+ security= [SECURITY] Choose a security module to enable at boot.
+ If this boot parameter is not specified, only the first
+ security module asking for security registration will be
+diff --git a/kernel/cred.c b/kernel/cred.c
+index e0573a4..c3f4e3e 100644
+--- a/kernel/cred.c
++++ b/kernel/cred.c
+@@ -565,6 +565,23 @@ void __init cred_init(void)
+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ }
+
++void __init secureboot_enable()
++{
++ pr_info("Secure boot enabled\n");
++ cap_lower((&init_cred)->cap_bset, CAP_COMPROMISE_KERNEL);
++ cap_lower((&init_cred)->cap_permitted, CAP_COMPROMISE_KERNEL);
++}
++
++/* Dummy Secure Boot enable option to fake out UEFI SB=1 */
++static int __init secureboot_enable_opt(char *str)
++{
++ int sb_enable = !!simple_strtol(str, NULL, 0);
++ if (sb_enable)
++ secureboot_enable();
++ return 1;
++}
++__setup("secureboot_enable=", secureboot_enable_opt);
++
+ /**
+ * prepare_kernel_cred - Prepare a set of credentials for a kernel service
+ * @daemon: A userspace daemon to be used as a reference
+--
+1.8.1.2
+
+
+From 4eb5ffe8e7d462f431da2714feb617d82fc50893 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Thu, 20 Sep 2012 10:41:03 -0400
+Subject: [PATCH 31/46] efi: Enable secure boot lockdown automatically when
+ enabled in firmware
+
+The firmware has a set of flags that indicate whether secure boot is enabled
+and enforcing. Use them to indicate whether the kernel should lock itself
+down. We also indicate the machine is in secure boot mode by adding the
+EFI_SECURE_BOOT bit for use with efi_enabled.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ Documentation/x86/zero-page.txt | 2 ++
+ arch/x86/boot/compressed/eboot.c | 32 ++++++++++++++++++++++++++++++++
+ arch/x86/include/uapi/asm/bootparam.h | 3 ++-
+ arch/x86/kernel/setup.c | 7 +++++++
+ include/linux/cred.h | 2 ++
+ include/linux/efi.h | 1 +
+ 6 files changed, 46 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
+index 199f453..ff651d3 100644
+--- a/Documentation/x86/zero-page.txt
++++ b/Documentation/x86/zero-page.txt
+@@ -30,6 +30,8 @@ Offset Proto Name Meaning
+ 1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below)
+ 1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer
+ (below)
++1EB/001 ALL kbd_status Numlock is enabled
++1EC/001 ALL secure_boot Kernel should enable secure boot lockdowns
+ 1EF/001 ALL sentinel Used to detect broken bootloaders
+ 290/040 ALL edd_mbr_sig_buffer EDD MBR signatures
+ 2D0/A00 ALL e820_map E820 memory map table
+diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
+index f8fa411..96bd86b 100644
+--- a/arch/x86/boot/compressed/eboot.c
++++ b/arch/x86/boot/compressed/eboot.c
+@@ -849,6 +849,36 @@ fail:
+ return status;
+ }
+
++static int get_secure_boot(efi_system_table_t *_table)
++{
++ u8 sb, setup;
++ unsigned long datasize = sizeof(sb);
++ efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
++ efi_status_t status;
++
++ status = efi_call_phys5(sys_table->runtime->get_variable,
++ L"SecureBoot", &var_guid, NULL, &datasize, &sb);
++
++ if (status != EFI_SUCCESS)
++ return 0;
++
++ if (sb == 0)
++ return 0;
++
++
++ status = efi_call_phys5(sys_table->runtime->get_variable,
++ L"SetupMode", &var_guid, NULL, &datasize,
++ &setup);
++
++ if (status != EFI_SUCCESS)
++ return 0;
++
++ if (setup == 1)
++ return 0;
++
++ return 1;
++}
++
+ /*
+ * Because the x86 boot code expects to be passed a boot_params we
+ * need to create one ourselves (usually the bootloader would create
+@@ -1143,6 +1173,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
+ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
+ goto fail;
+
++ boot_params->secure_boot = get_secure_boot(sys_table);
++
+ setup_graphics(boot_params);
+
+ setup_efi_pci(boot_params);
+diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
+index c15ddaf..85d7685 100644
+--- a/arch/x86/include/uapi/asm/bootparam.h
++++ b/arch/x86/include/uapi/asm/bootparam.h
+@@ -131,7 +131,8 @@ struct boot_params {
+ __u8 eddbuf_entries; /* 0x1e9 */
+ __u8 edd_mbr_sig_buf_entries; /* 0x1ea */
+ __u8 kbd_status; /* 0x1eb */
+- __u8 _pad5[3]; /* 0x1ec */
++ __u8 secure_boot; /* 0x1ec */
++ __u8 _pad5[2]; /* 0x1ed */
+ /*
+ * The sentinel is set to a nonzero value (0xff) in header.S.
+ *
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index 8b24289..d74b441 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -1042,6 +1042,13 @@ void __init setup_arch(char **cmdline_p)
+
+ io_delay_init();
+
++ if (boot_params.secure_boot) {
++#ifdef CONFIG_EFI
++ set_bit(EFI_SECURE_BOOT, &x86_efi_facility);
++#endif
++ secureboot_enable();
++ }
++
+ /*
+ * Parse the ACPI tables for possible boot-time SMP configuration.
+ */
+diff --git a/include/linux/cred.h b/include/linux/cred.h
+index 04421e8..9e69542 100644
+--- a/include/linux/cred.h
++++ b/include/linux/cred.h
+@@ -156,6 +156,8 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
+ extern int set_create_files_as(struct cred *, struct inode *);
+ extern void __init cred_init(void);
+
++extern void secureboot_enable(void);
++
+ /*
+ * check for validity of credentials
+ */
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 7a9498a..1ae16b6 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -627,6 +627,7 @@ extern int __init efi_setup_pcdp_console(char *);
+ #define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */
+ #define EFI_MEMMAP 4 /* Can we use EFI memory map? */
+ #define EFI_64BIT 5 /* Is the firmware 64-bit? */
++#define EFI_SECURE_BOOT 6 /* Are we in Secure Boot mode? */
+
+ #ifdef CONFIG_EFI
+ # ifdef CONFIG_X86
+--
+1.8.1.2
+
+
+From 66e152817df3a3856ae268ae7c817b42f23d3e55 Mon Sep 17 00:00:00 2001
+From: Dave Howells <dhowells@redhat.com>
+Date: Tue, 23 Oct 2012 09:30:54 -0400
+Subject: [PATCH 32/46] Add EFI signature data types
+
+Add the data types that are used for containing hashes, keys and certificates
+for cryptographic verification.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ include/linux/efi.h | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 1ae16b6..de7021d 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -388,6 +388,12 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
+ #define EFI_FILE_SYSTEM_GUID \
+ EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+
++#define EFI_CERT_SHA256_GUID \
++ EFI_GUID( 0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 )
++
++#define EFI_CERT_X509_GUID \
++ EFI_GUID( 0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
++
+ typedef struct {
+ efi_guid_t guid;
+ u64 table;
+@@ -523,6 +529,20 @@ typedef struct {
+
+ #define EFI_INVALID_TABLE_ADDR (~0UL)
+
++typedef struct {
++ efi_guid_t signature_owner;
++ u8 signature_data[];
++} efi_signature_data_t;
++
++typedef struct {
++ efi_guid_t signature_type;
++ u32 signature_list_size;
++ u32 signature_header_size;
++ u32 signature_size;
++ u8 signature_header[];
++ /* efi_signature_data_t signatures[][] */
++} efi_signature_list_t;
++
+ /*
+ * All runtime access to EFI goes through this structure:
+ */
+--
+1.8.1.2
+
+
+From 620c32412493f6a5e961a2e7636c8785c14ff21e Mon Sep 17 00:00:00 2001
+From: Dave Howells <dhowells@redhat.com>
+Date: Tue, 23 Oct 2012 09:36:28 -0400
+Subject: [PATCH 33/46] Add an EFI signature blob parser and key loader.
+
+X.509 certificates are loaded into the specified keyring as asymmetric type
+keys.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+---
+ crypto/asymmetric_keys/Kconfig | 8 +++
+ crypto/asymmetric_keys/Makefile | 1 +
+ crypto/asymmetric_keys/efi_parser.c | 109 ++++++++++++++++++++++++++++++++++++
+ include/linux/efi.h | 4 ++
+ 4 files changed, 122 insertions(+)
+ create mode 100644 crypto/asymmetric_keys/efi_parser.c
+
+diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
+index 2777916..429bbb7 100644
+--- a/crypto/asymmetric_keys/Kconfig
++++ b/crypto/asymmetric_keys/Kconfig
+@@ -53,4 +53,12 @@ config PE_FILE_PARSER
+ This option provides support for parsing signed PE binaries that
+ contain an X.509 certificate in an internal section.
+
++config EFI_SIGNATURE_LIST_PARSER
++ bool "EFI signature list parser"
++ depends on EFI
++ select X509_CERTIFICATE_PARSER
++ help
++ This option provides support for parsing EFI signature lists for
++ X.509 certificates and turning them into keys.
++
+ endif # ASYMMETRIC_KEY_TYPE
+diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
+index ddc64bb..360b308 100644
+--- a/crypto/asymmetric_keys/Makefile
++++ b/crypto/asymmetric_keys/Makefile
+@@ -8,6 +8,7 @@ asymmetric_keys-y := asymmetric_type.o signature.o
+
+ obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+ obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
++obj-$(CONFIG_EFI_SIGNATURE_LIST_PARSER) += efi_parser.o
+
+ #
+ # X.509 Certificate handling
+diff --git a/crypto/asymmetric_keys/efi_parser.c b/crypto/asymmetric_keys/efi_parser.c
+new file mode 100644
+index 0000000..424896a
+--- /dev/null
++++ b/crypto/asymmetric_keys/efi_parser.c
+@@ -0,0 +1,109 @@
++/* EFI signature/key/certificate list parser
++ *
++ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
++ * Written by David Howells (dhowells@redhat.com)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public Licence
++ * as published by the Free Software Foundation; either version
++ * 2 of the Licence, or (at your option) any later version.
++ */
++
++#define pr_fmt(fmt) "EFI: "fmt
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/err.h>
++#include <linux/efi.h>
++#include <keys/asymmetric-type.h>
++
++static __initdata efi_guid_t efi_cert_x509_guid = EFI_CERT_X509_GUID;
++
++/**
++ * parse_efi_signature_list - Parse an EFI signature list for certificates
++ * @data: The data blob to parse
++ * @size: The size of the data blob
++ * @keyring: The keyring to add extracted keys to
++ */
++int __init parse_efi_signature_list(const void *data, size_t size, struct key *keyring)
++{
++ unsigned offs = 0;
++ size_t lsize, esize, hsize, elsize;
++
++ pr_devel("-->%s(,%zu)\n", __func__, size);
++
++ while (size > 0) {
++ efi_signature_list_t list;
++ const efi_signature_data_t *elem;
++ key_ref_t key;
++
++ if (size < sizeof(list))
++ return -EBADMSG;
++
++ memcpy(&list, data, sizeof(list));
++ pr_devel("LIST[%04x] guid=%pUl ls=%x hs=%x ss=%x\n",
++ offs,
++ list.signature_type.b, list.signature_list_size,
++ list.signature_header_size, list.signature_size);
++
++ lsize = list.signature_list_size;
++ hsize = list.signature_header_size;
++ esize = list.signature_size;
++ elsize = lsize - sizeof(list) - hsize;
++
++ if (lsize > size) {
++ pr_devel("<--%s() = -EBADMSG [overrun @%x]\n",
++ __func__, offs);
++ return -EBADMSG;
++ }
++ if (lsize < sizeof(list) ||
++ lsize - sizeof(list) < hsize ||
++ esize < sizeof(*elem) ||
++ elsize < esize ||
++ elsize % esize != 0) {
++ pr_devel("- bad size combo @%x\n", offs);
++ return -EBADMSG;
++ }
++
++ if (efi_guidcmp(list.signature_type, efi_cert_x509_guid) != 0) {
++ data += lsize;
++ size -= lsize;
++ offs += lsize;
++ continue;
++ }
++
++ data += sizeof(list) + hsize;
++ size -= sizeof(list) + hsize;
++ offs += sizeof(list) + hsize;
++
++ for (; elsize > 0; elsize -= esize) {
++ elem = data;
++
++ pr_devel("ELEM[%04x]\n", offs);
++
++ key = key_create_or_update(
++ make_key_ref(keyring, 1),
++ "asymmetric",
++ NULL,
++ &elem->signature_data,
++ esize - sizeof(*elem),
++ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
++ KEY_USR_VIEW,
++ KEY_ALLOC_NOT_IN_QUOTA |
++ KEY_ALLOC_TRUSTED);
++
++ if (IS_ERR(key))
++ pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
++ PTR_ERR(key));
++ else
++ pr_notice("Loaded cert '%s' linked to '%s'\n",
++ key_ref_to_ptr(key)->description,
++ keyring->description);
++
++ data += esize;
++ size -= esize;
++ offs += esize;
++ }
++ }
++
++ return 0;
++}
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index de7021d..64b3e55 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -612,6 +612,10 @@ extern int efi_set_rtc_mmss(unsigned long nowtime);
+ extern void efi_reserve_boot_services(void);
+ extern struct efi_memory_map memmap;
+
++struct key;
++extern int __init parse_efi_signature_list(const void *data, size_t size,
++ struct key *keyring);
++
+ /**
+ * efi_range_is_wc - check the WC bit on an address range
+ * @start: starting kvirt address
+--
+1.8.1.2
+
+
+From 03476516aa5a12706ee151344b36f759c67a5030 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 26 Oct 2012 12:36:24 -0400
+Subject: [PATCH 34/46] KEYS: Add a system blacklist keyring
+
+This adds an additional keyring that is used to store certificates that
+are blacklisted. This keyring is searched first when loading signed modules
+and if the module's certificate is found, it will refuse to load. This is
+useful in cases where third party certificates are used for module signing.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ include/keys/system_keyring.h | 4 ++++
+ init/Kconfig | 9 +++++++++
+ kernel/module_signing.c | 12 ++++++++++++
+ kernel/system_keyring.c | 17 +++++++++++++++++
+ 4 files changed, 42 insertions(+)
+
+diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
+index 8dabc39..e466de1 100644
+--- a/include/keys/system_keyring.h
++++ b/include/keys/system_keyring.h
+@@ -18,6 +18,10 @@
+
+ extern struct key *system_trusted_keyring;
+
++#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
++extern struct key *system_blacklist_keyring;
++#endif
++
+ #endif
+
+ #endif /* _KEYS_SYSTEM_KEYRING_H */
+diff --git a/init/Kconfig b/init/Kconfig
+index e05877b..2e82b25 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1580,6 +1580,15 @@ config SYSTEM_TRUSTED_KEYRING
+
+ Keys in this keyring are used by module signature checking.
+
++config SYSTEM_BLACKLIST_KEYRING
++ bool "Provide system-wide ring of blacklisted keys"
++ depends on KEYS
++ help
++ Provide a system keyring to which blacklisted keys can be added. Keys
++ in the keyring are considered entirely untrusted. Keys in this keyring
++ are used by the module signature checking to reject loading of modules
++ signed with a blacklisted key.
++
+ menuconfig MODULES
+ bool "Enable loadable module support"
+ help
+diff --git a/kernel/module_signing.c b/kernel/module_signing.c
+index 0b6b870..0a29b40 100644
+--- a/kernel/module_signing.c
++++ b/kernel/module_signing.c
+@@ -158,6 +158,18 @@ static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
+
+ pr_debug("Look up: \"%s\"\n", id);
+
++#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
++ key = keyring_search(make_key_ref(system_blacklist_keyring, 1),
++ &key_type_asymmetric, id);
++ if (!IS_ERR(key)) {
++ /* module is signed with a cert in the blacklist. reject */
++ pr_err("Module key '%s' is in blacklist\n", id);
++ key_ref_put(key);
++ kfree(id);
++ return ERR_PTR(-EKEYREJECTED);
++ }
++#endif
++
+ key = keyring_search(make_key_ref(system_trusted_keyring, 1),
+ &key_type_asymmetric, id);
+ if (IS_ERR(key))
+diff --git a/kernel/system_keyring.c b/kernel/system_keyring.c
+index dae8778..2913c70 100644
+--- a/kernel/system_keyring.c
++++ b/kernel/system_keyring.c
+@@ -20,6 +20,9 @@
+
+ struct key *system_trusted_keyring;
+ EXPORT_SYMBOL_GPL(system_trusted_keyring);
++#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
++struct key *system_blacklist_keyring;
++#endif
+
+ extern __initdata const u8 system_certificate_list[];
+ extern __initdata const u8 system_certificate_list_end[];
+@@ -41,6 +44,20 @@ static __init int system_trusted_keyring_init(void)
+ panic("Can't allocate system trusted keyring\n");
+
+ set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
++
++#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
++ system_blacklist_keyring = keyring_alloc(".system_blacklist_keyring",
++ KUIDT_INIT(0), KGIDT_INIT(0),
++ current_cred(),
++ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
++ KEY_USR_VIEW | KEY_USR_READ,
++ KEY_ALLOC_NOT_IN_QUOTA, NULL);
++ if (IS_ERR(system_blacklist_keyring))
++ panic("Can't allocate system blacklist keyring\n");
++
++ set_bit(KEY_FLAG_TRUSTED_ONLY, &system_blacklist_keyring->flags);
++#endif
++
+ return 0;
+ }
+
+--
+1.8.1.2
+
+
+From 8ac54dcfcae74c88919cf4713bf5e3946ed7d6df Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 26 Oct 2012 12:42:16 -0400
+Subject: [PATCH 35/46] MODSIGN: Import certificates from UEFI Secure Boot
+
+Secure Boot stores a list of allowed certificates in the 'db' variable.
+This imports those certificates into the system trusted keyring. This
+allows for a third party signing certificate to be used in conjunction
+with signed modules. By importing the public certificate into the 'db'
+variable, a user can allow a module signed with that certificate to
+load. The shim UEFI bootloader has a similar certificate list stored
+in the 'MokListRT' variable. We import those as well.
+
+In the opposite case, Secure Boot maintains a list of disallowed
+certificates in the 'dbx' variable. We load those certificates into
+the newly introduced system blacklist keyring and forbid any module
+signed with those from loading.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ include/linux/efi.h | 6 ++++
+ init/Kconfig | 9 +++++
+ kernel/Makefile | 3 ++
+ kernel/modsign_uefi.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 109 insertions(+)
+ create mode 100644 kernel/modsign_uefi.c
+
+diff --git a/include/linux/efi.h b/include/linux/efi.h
+index 64b3e55..76fe526 100644
+--- a/include/linux/efi.h
++++ b/include/linux/efi.h
+@@ -394,6 +394,12 @@ typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules,
+ #define EFI_CERT_X509_GUID \
+ EFI_GUID( 0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 )
+
++#define EFI_IMAGE_SECURITY_DATABASE_GUID \
++ EFI_GUID( 0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f )
++
++#define EFI_SHIM_LOCK_GUID \
++ EFI_GUID( 0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 )
++
+ typedef struct {
+ efi_guid_t guid;
+ u64 table;
+diff --git a/init/Kconfig b/init/Kconfig
+index 2e82b25..143f898 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1687,6 +1687,15 @@ config MODULE_SIG_FORCE
+ Reject unsigned modules or signed modules for which we don't have a
+ key. Without this, such modules will simply taint the kernel.
+
++config MODULE_SIG_UEFI
++ bool "Allow modules signed with certs stored in UEFI"
++ depends on MODULE_SIG && SYSTEM_BLACKLIST_KEYRING && EFI
++ select EFI_SIGNATURE_LIST_PARSER
++ help
++ This will import certificates stored in UEFI and allow modules
++ signed with those to be loaded. It will also disallow loading
++ of modules stored in the UEFI dbx variable.
++
+ choice
+ prompt "Which hash algorithm should modules be signed with?"
+ depends on MODULE_SIG
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 0ca8c0a..25af667 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -56,6 +56,7 @@ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
+ obj-$(CONFIG_MODULES) += module.o
+ obj-$(CONFIG_MODULE_SIG) += module_signing.o
++obj-$(CONFIG_MODULE_SIG_UEFI) += modsign_uefi.o
+ obj-$(CONFIG_KALLSYMS) += kallsyms.o
+ obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+ obj-$(CONFIG_KEXEC) += kexec.o
+@@ -115,6 +116,8 @@ obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
+
+ $(obj)/configs.o: $(obj)/config_data.h
+
++$(obj)/modsign_uefi.o: KBUILD_CFLAGS += -fshort-wchar
++
+ # config_data.h contains the same information as ikconfig.h but gzipped.
+ # Info from config_data can be extracted from /proc/config*
+ targets += config_data.gz
+diff --git a/kernel/modsign_uefi.c b/kernel/modsign_uefi.c
+new file mode 100644
+index 0000000..df831ff
+--- /dev/null
++++ b/kernel/modsign_uefi.c
+@@ -0,0 +1,91 @@
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/cred.h>
++#include <linux/err.h>
++#include <linux/efi.h>
++#include <keys/asymmetric-type.h>
++#include <keys/system_keyring.h>
++#include "module-internal.h"
++
++static __init void *get_cert_list(efi_char16_t *name, efi_guid_t *guid, unsigned long *size)
++{
++ efi_status_t status;
++ unsigned long lsize = 4;
++ unsigned long tmpdb[4];
++ void *db = NULL;
++
++ status = efi.get_variable(name, guid, NULL, &lsize, &tmpdb);
++ if (status != EFI_BUFFER_TOO_SMALL) {
++ pr_err("Couldn't get size: 0x%lx\n", status);
++ return NULL;
++ }
++
++ db = kmalloc(lsize, GFP_KERNEL);
++ if (!db) {
++ pr_err("Couldn't allocate memory for uefi cert list\n");
++ goto out;
++ }
++
++ status = efi.get_variable(name, guid, NULL, &lsize, db);
++ if (status != EFI_SUCCESS) {
++ kfree(db);
++ db = NULL;
++ pr_err("Error reading db var: 0x%lx\n", status);
++ }
++out:
++ *size = lsize;
++ return db;
++}
++
++/*
++ * * Load the certs contained in the UEFI databases
++ * */
++static int __init load_uefi_certs(void)
++{
++ efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
++ efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
++ void *db = NULL, *dbx = NULL, *mok = NULL;
++ unsigned long dbsize = 0, dbxsize = 0, moksize = 0;
++ int rc = 0;
++
++ /* Check if SB is enabled and just return if not */
++ if (!efi_enabled(EFI_SECURE_BOOT))
++ return 0;
++
++ /* Get db, MokListRT, and dbx. They might not exist, so it isn't
++ * an error if we can't get them.
++ */
++ db = get_cert_list(L"db", &secure_var, &dbsize);
++ if (!db) {
++ pr_err("MODSIGN: Couldn't get UEFI db list\n");
++ } else {
++ rc = parse_efi_signature_list(db, dbsize, system_trusted_keyring);
++ if (rc)
++ pr_err("Couldn't parse db signatures: %d\n", rc);
++ kfree(db);
++ }
++
++ mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
++ if (!mok) {
++ pr_info("MODSIGN: Couldn't get UEFI MokListRT\n");
++ } else {
++ rc = parse_efi_signature_list(mok, moksize, system_trusted_keyring);
++ if (rc)
++ pr_err("Couldn't parse MokListRT signatures: %d\n", rc);
++ kfree(mok);
++ }
++
++ dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
++ if (!dbx) {
++ pr_info("MODSIGN: Couldn't get UEFI dbx list\n");
++ } else {
++ rc = parse_efi_signature_list(dbx, dbxsize,
++ system_blacklist_keyring);
++ if (rc)
++ pr_err("Couldn't parse dbx signatures: %d\n", rc);
++ kfree(dbx);
++ }
++
++ return rc;
++}
++late_initcall(load_uefi_certs);
+--
+1.8.1.2
+
+
+From 14963f73dc1daf7932262c4128a49bf4c2737ac3 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Thu, 20 Sep 2012 10:40:57 -0400
+Subject: [PATCH 36/46] PCI: Lock down BAR access in secure boot environments
+
+Any hardware that can potentially generate DMA has to be locked down from
+userspace in order to avoid it being possible for an attacker to cause
+arbitrary kernel behaviour. Default to paranoid - in future we can
+potentially relax this for sufficiently IOMMU-isolated devices.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+---
+ drivers/pci/pci-sysfs.c | 9 +++++++++
+ drivers/pci/proc.c | 8 +++++++-
+ drivers/pci/syscall.c | 2 +-
+ 3 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
+index 9c6e9bb..b966089 100644
+--- a/drivers/pci/pci-sysfs.c
++++ b/drivers/pci/pci-sysfs.c
+@@ -622,6 +622,9 @@ pci_write_config(struct file* filp, struct kobject *kobj,
+ loff_t init_off = off;
+ u8 *data = (u8*) buf;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ if (off > dev->cfg_size)
+ return 0;
+ if (off + count > dev->cfg_size) {
+@@ -928,6 +931,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
+ resource_size_t start, end;
+ int i;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ for (i = 0; i < PCI_ROM_RESOURCE; i++)
+ if (res == &pdev->resource[i])
+ break;
+@@ -1035,6 +1041,9 @@ pci_write_resource_io(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+ {
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ return pci_resource_io(filp, kobj, attr, buf, off, count, true);
+ }
+
+diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
+index 9b8505c..35580bc 100644
+--- a/drivers/pci/proc.c
++++ b/drivers/pci/proc.c
+@@ -139,6 +139,9 @@ proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, lof
+ int size = dp->size;
+ int cnt;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ if (pos >= size)
+ return 0;
+ if (nbytes >= size)
+@@ -219,6 +222,9 @@ static long proc_bus_pci_ioctl(struct file *file, unsigned int cmd,
+ #endif /* HAVE_PCI_MMAP */
+ int ret = 0;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ switch (cmd) {
+ case PCIIOC_CONTROLLER:
+ ret = pci_domain_nr(dev->bus);
+@@ -259,7 +265,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
+ struct pci_filp_private *fpriv = file->private_data;
+ int i, ret;
+
+- if (!capable(CAP_SYS_RAWIO))
++ if (!capable(CAP_SYS_RAWIO) || !capable(CAP_COMPROMISE_KERNEL))
+ return -EPERM;
+
+ /* Make sure the caller is mapping a real resource for this device */
+diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
+index e1c1ec5..97e785f 100644
+--- a/drivers/pci/syscall.c
++++ b/drivers/pci/syscall.c
+@@ -92,7 +92,7 @@ SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
+ u32 dword;
+ int err = 0;
+
+- if (!capable(CAP_SYS_ADMIN))
++ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_COMPROMISE_KERNEL))
+ return -EPERM;
+
+ dev = pci_get_bus_and_slot(bus, dfn);
+--
+1.8.1.2
+
+
+From 0795d98bc16865e22d35e43534b2db96fc140cd1 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Thu, 20 Sep 2012 10:40:58 -0400
+Subject: [PATCH 37/46] x86: Lock down IO port access in secure boot
+ environments
+
+IO port access would permit users to gain access to PCI configuration
+registers, which in turn (on a lot of hardware) give access to MMIO register
+space. This would potentially permit root to trigger arbitrary DMA, so lock
+it down by default.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+---
+ arch/x86/kernel/ioport.c | 4 ++--
+ drivers/char/mem.c | 3 +++
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c
+index 8c96897..a2578c4 100644
+--- a/arch/x86/kernel/ioport.c
++++ b/arch/x86/kernel/ioport.c
+@@ -28,7 +28,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
+
+ if ((from + num <= from) || (from + num > IO_BITMAP_BITS))
+ return -EINVAL;
+- if (turn_on && !capable(CAP_SYS_RAWIO))
++ if (turn_on && (!capable(CAP_SYS_RAWIO) || !capable(CAP_COMPROMISE_KERNEL)))
+ return -EPERM;
+
+ /*
+@@ -102,7 +102,7 @@ long sys_iopl(unsigned int level, struct pt_regs *regs)
+ return -EINVAL;
+ /* Trying to gain more privileges? */
+ if (level > old) {
+- if (!capable(CAP_SYS_RAWIO))
++ if (!capable(CAP_SYS_RAWIO) || !capable(CAP_COMPROMISE_KERNEL))
+ return -EPERM;
+ }
+ regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12);
+diff --git a/drivers/char/mem.c b/drivers/char/mem.c
+index c6fa3bc..fc28099 100644
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -597,6 +597,9 @@ static ssize_t write_port(struct file *file, const char __user *buf,
+ unsigned long i = *ppos;
+ const char __user * tmp = buf;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ if (!access_ok(VERIFY_READ, buf, count))
+ return -EFAULT;
+ while (count-- > 0 && i < 65536) {
+--
+1.8.1.2
+
+
+From 22aed1e0667a2032e407c3faafeed1503abd3f22 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Thu, 20 Sep 2012 10:40:59 -0400
+Subject: [PATCH 38/46] ACPI: Limit access to custom_method
+
+It must be impossible for even root to get code executed in kernel context
+under a secure boot environment. custom_method effectively allows arbitrary
+access to system memory, so it needs to have a capability check here.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+---
+ drivers/acpi/custom_method.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
+index 5d42c24..247d58b 100644
+--- a/drivers/acpi/custom_method.c
++++ b/drivers/acpi/custom_method.c
+@@ -29,6 +29,9 @@ static ssize_t cm_write(struct file *file, const char __user * user_buf,
+ struct acpi_table_header table;
+ acpi_status status;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ if (!(*ppos)) {
+ /* parse the table header to get the table length */
+ if (count <= sizeof(struct acpi_table_header))
+--
+1.8.1.2
+
+
+From f283bb6b091b903122ac1d75da3e73c078402cf1 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Thu, 20 Sep 2012 10:41:00 -0400
+Subject: [PATCH 39/46] asus-wmi: Restrict debugfs interface
+
+We have no way of validating what all of the Asus WMI methods do on a
+given machine, and there's a risk that some will allow hardware state to
+be manipulated in such a way that arbitrary code can be executed in the
+kernel. Add a capability check to prevent that.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+---
+ drivers/platform/x86/asus-wmi.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index f80ae4d..059195f 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -1521,6 +1521,9 @@ static int show_dsts(struct seq_file *m, void *data)
+ int err;
+ u32 retval = -1;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
+
+ if (err < 0)
+@@ -1537,6 +1540,9 @@ static int show_devs(struct seq_file *m, void *data)
+ int err;
+ u32 retval = -1;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param,
+ &retval);
+
+@@ -1561,6 +1567,9 @@ static int show_call(struct seq_file *m, void *data)
+ union acpi_object *obj;
+ acpi_status status;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID,
+ 1, asus->debug.method_id,
+ &input, &output);
+--
+1.8.1.2
+
+
+From f8aa6f1cf4fbd8c4431dc71d718365ee7e59c961 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Thu, 20 Sep 2012 10:41:01 -0400
+Subject: [PATCH 40/46] Restrict /dev/mem and /dev/kmem in secure boot setups
+
+Allowing users to write to address space makes it possible for the kernel
+to be subverted. Restrict this when we need to protect the kernel.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+---
+ drivers/char/mem.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/char/mem.c b/drivers/char/mem.c
+index fc28099..b5df7a8 100644
+--- a/drivers/char/mem.c
++++ b/drivers/char/mem.c
+@@ -158,6 +158,9 @@ static ssize_t write_mem(struct file *file, const char __user *buf,
+ unsigned long copied;
+ void *ptr;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ if (!valid_phys_addr_range(p, count))
+ return -EFAULT;
+
+@@ -530,6 +533,9 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
+ char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
+ int err = 0;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ if (p < (unsigned long) high_memory) {
+ unsigned long to_write = min_t(unsigned long, count,
+ (unsigned long)high_memory - p);
+--
+1.8.1.2
+
+
+From 0363f298cfa74fb6d3f01f3351b2a4cad2e25d8f Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Thu, 20 Sep 2012 10:41:04 -0400
+Subject: [PATCH 41/46] acpi: Ignore acpi_rsdp kernel parameter in a secure
+ boot environment
+
+This option allows userspace to pass the RSDP address to the kernel. This
+could potentially be used to circumvent the secure boot trust model.
+This is setup through the setup_arch function, which is called before the
+security_init function sets up the security_ops, so we cannot use a
+capable call here. We ignore the setting if we are booted in Secure Boot
+mode.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ drivers/acpi/osl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
+index bd22f86..d68c04f 100644
+--- a/drivers/acpi/osl.c
++++ b/drivers/acpi/osl.c
+@@ -246,7 +246,7 @@ early_param("acpi_rsdp", setup_acpi_rsdp);
+ acpi_physical_address __init acpi_os_get_root_pointer(void)
+ {
+ #ifdef CONFIG_KEXEC
+- if (acpi_rsdp)
++ if (acpi_rsdp && !efi_enabled(EFI_SECURE_BOOT))
+ return acpi_rsdp;
+ #endif
+
+--
+1.8.1.2
+
+
+From 40ec2252761b1574d3ee0ed639b117e40075cdee Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg@redhat.com>
+Date: Tue, 4 Sep 2012 11:55:13 -0400
+Subject: [PATCH 42/46] kexec: Disable in a secure boot environment
+
+kexec could be used as a vector for a malicious user to use a signed kernel
+to circumvent the secure boot trust model. In the long run we'll want to
+support signed kexec payloads, but for the moment we should just disable
+loading entirely in that situation.
+
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+---
+ kernel/kexec.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/kernel/kexec.c b/kernel/kexec.c
+index 5e4bd78..dd464e0 100644
+--- a/kernel/kexec.c
++++ b/kernel/kexec.c
+@@ -943,7 +943,7 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments,
+ int result;
+
+ /* We only trust the superuser with rebooting the system. */
+- if (!capable(CAP_SYS_BOOT))
++ if (!capable(CAP_SYS_BOOT) || !capable(CAP_COMPROMISE_KERNEL))
+ return -EPERM;
+
+ /*
+--
+1.8.1.2
+
+
+From f2242ba8cc35f8a89e7a8df46fac08bed9b86080 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 5 Oct 2012 10:12:48 -0400
+Subject: [PATCH 43/46] MODSIGN: Always enforce module signing in a Secure Boot
+ environment
+
+If a machine is booted into a Secure Boot environment, we need to
+protect the trust model. This requires that all modules be signed
+with a key that is in the kernel's _modsign keyring. The checks for
+this are already done via the 'sig_enforce' module parameter. Make
+this visible within the kernel and force it to be true.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ kernel/cred.c | 8 ++++++++
+ kernel/module.c | 4 ++--
+ 2 files changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/cred.c b/kernel/cred.c
+index c3f4e3e..c5554e0 100644
+--- a/kernel/cred.c
++++ b/kernel/cred.c
+@@ -565,11 +565,19 @@ void __init cred_init(void)
+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ }
+
++#ifdef CONFIG_MODULE_SIG
++extern bool sig_enforce;
++#endif
++
+ void __init secureboot_enable()
+ {
+ pr_info("Secure boot enabled\n");
+ cap_lower((&init_cred)->cap_bset, CAP_COMPROMISE_KERNEL);
+ cap_lower((&init_cred)->cap_permitted, CAP_COMPROMISE_KERNEL);
++#ifdef CONFIG_MODULE_SIG
++ /* Enable module signature enforcing */
++ sig_enforce = true;
++#endif
+ }
+
+ /* Dummy Secure Boot enable option to fake out UEFI SB=1 */
+diff --git a/kernel/module.c b/kernel/module.c
+index eab0827..93a16dc 100644
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -109,9 +109,9 @@ struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
+
+ #ifdef CONFIG_MODULE_SIG
+ #ifdef CONFIG_MODULE_SIG_FORCE
+-static bool sig_enforce = true;
++bool sig_enforce = true;
+ #else
+-static bool sig_enforce = false;
++bool sig_enforce = false;
+
+ static int param_set_bool_enable_only(const char *val,
+ const struct kernel_param *kp)
+--
+1.8.1.2
+
+
+From 5356f058f306024cb085b6b2c6ba39407a3a2fae Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Fri, 26 Oct 2012 14:02:09 -0400
+Subject: [PATCH 44/46] hibernate: Disable in a Secure Boot environment
+
+There is currently no way to verify the resume image when returning
+from hibernate. This might compromise the secure boot trust model,
+so until we can work with signed hibernate images we disable it in
+a Secure Boot environment.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ kernel/power/hibernate.c | 15 ++++++++++++++-
+ kernel/power/main.c | 7 ++++++-
+ kernel/power/user.c | 3 +++
+ 3 files changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
+index b26f5f1..7f63cb4 100644
+--- a/kernel/power/hibernate.c
++++ b/kernel/power/hibernate.c
+@@ -28,6 +28,7 @@
+ #include <linux/syscore_ops.h>
+ #include <linux/ctype.h>
+ #include <linux/genhd.h>
++#include <linux/efi.h>
+
+ #include "power.h"
+
+@@ -632,6 +633,10 @@ int hibernate(void)
+ {
+ int error;
+
++ if (!capable(CAP_COMPROMISE_KERNEL)) {
++ return -EPERM;
++ }
++
+ lock_system_sleep();
+ /* The snapshot device should not be opened while we're running */
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+@@ -723,7 +728,7 @@ static int software_resume(void)
+ /*
+ * If the user said "noresume".. bail out early.
+ */
+- if (noresume)
++ if (noresume || !capable(CAP_COMPROMISE_KERNEL))
+ return 0;
+
+ /*
+@@ -889,6 +894,11 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
+ int i;
+ char *start = buf;
+
++ if (efi_enabled(EFI_SECURE_BOOT)) {
++ buf += sprintf(buf, "[%s]\n", "disabled");
++ return buf-start;
++ }
++
+ for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+ if (!hibernation_modes[i])
+ continue;
+@@ -923,6 +933,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
+ char *p;
+ int mode = HIBERNATION_INVALID;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ p = memchr(buf, '\n', n);
+ len = p ? p - buf : n;
+
+diff --git a/kernel/power/main.c b/kernel/power/main.c
+index 1c16f91..4f915fc 100644
+--- a/kernel/power/main.c
++++ b/kernel/power/main.c
+@@ -15,6 +15,7 @@
+ #include <linux/workqueue.h>
+ #include <linux/debugfs.h>
+ #include <linux/seq_file.h>
++#include <linux/efi.h>
+
+ #include "power.h"
+
+@@ -301,7 +302,11 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
+ }
+ #endif
+ #ifdef CONFIG_HIBERNATION
+- s += sprintf(s, "%s\n", "disk");
++ if (!efi_enabled(EFI_SECURE_BOOT)) {
++ s += sprintf(s, "%s\n", "disk");
++ } else {
++ s += sprintf(s, "\n");
++ }
+ #else
+ if (s != buf)
+ /* convert the last space to a newline */
+diff --git a/kernel/power/user.c b/kernel/power/user.c
+index 4ed81e7..b11a0f4 100644
+--- a/kernel/power/user.c
++++ b/kernel/power/user.c
+@@ -48,6 +48,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
+ struct snapshot_data *data;
+ int error;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ lock_system_sleep();
+
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+--
+1.8.1.2
+
+
+From 063f12d80498c1c2799022ced6aa1399234da409 Mon Sep 17 00:00:00 2001
+From: Josh Boyer <jwboyer@redhat.com>
+Date: Tue, 5 Feb 2013 19:25:05 -0500
+Subject: [PATCH 45/46] efi: Disable secure boot if shim is in insecure mode
+
+A user can manually tell the shim boot loader to disable validation of
+images it loads. When a user does this, it creates a UEFI variable called
+MokSBState that does not have the runtime attribute set. Given that the
+user explicitly disabled validation, we can honor that and not enable
+secure boot mode if that variable is set.
+
+Signed-off-by: Josh Boyer <jwboyer@redhat.com>
+---
+ arch/x86/boot/compressed/eboot.c | 20 +++++++++++++++++++-
+ 1 file changed, 19 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
+index 96bd86b..6e1331c 100644
+--- a/arch/x86/boot/compressed/eboot.c
++++ b/arch/x86/boot/compressed/eboot.c
+@@ -851,8 +851,9 @@ fail:
+
+ static int get_secure_boot(efi_system_table_t *_table)
+ {
+- u8 sb, setup;
++ u8 sb, setup, moksbstate;
+ unsigned long datasize = sizeof(sb);
++ u32 attr;
+ efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
+ efi_status_t status;
+
+@@ -876,6 +877,23 @@ static int get_secure_boot(efi_system_table_t *_table)
+ if (setup == 1)
+ return 0;
+
++ /* See if a user has put shim into insecure_mode. If so, and the variable
++ * doesn't have the runtime attribute set, we might as well honor that.
++ */
++ var_guid = EFI_SHIM_LOCK_GUID;
++ status = efi_call_phys5(sys_table->runtime->get_variable,
++ L"MokSBState", &var_guid, &attr, &datasize,
++ &moksbstate);
++
++ /* If it fails, we don't care why. Default to secure */
++ if (status != EFI_SUCCESS)
++ return 1;
++
++ if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS)) {
++ if (moksbstate == 1)
++ return 0;
++ }
++
+ return 1;
+ }
+
+--
+1.8.1.2
+
+
+From b8cdeb4d1ab3939d9c70e2377d22922ef74a38c7 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Fri, 8 Feb 2013 11:12:13 -0800
+Subject: [PATCH 46/46] x86: Lock down MSR writing in secure boot
+
+Writing to MSRs should not be allowed unless CAP_COMPROMISE_KERNEL is
+set since it could lead to execution of arbitrary code in kernel mode.
+
+Signed-off-by: Kees Cook <keescook@chromium.org>
+---
+ arch/x86/kernel/msr.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
+index 4929502..adaab3d 100644
+--- a/arch/x86/kernel/msr.c
++++ b/arch/x86/kernel/msr.c
+@@ -103,6 +103,9 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
+ int err = 0;
+ ssize_t bytes = 0;
+
++ if (!capable(CAP_COMPROMISE_KERNEL))
++ return -EPERM;
++
+ if (count % 8)
+ return -EINVAL; /* Invalid chunk size */
+
+@@ -150,6 +153,10 @@ static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg)
+ err = -EBADF;
+ break;
+ }
++ if (!capable(CAP_COMPROMISE_KERNEL)) {
++ err = -EPERM;
++ break;
++ }
+ if (copy_from_user(&regs, uregs, sizeof regs)) {
+ err = -EFAULT;
+ break;
+--
+1.8.1.2
+
diff --git a/freed-ora/current/master/kernel.spec b/freed-ora/current/master/kernel.spec
index bc354be08..196e683ef 100644
--- a/freed-ora/current/master/kernel.spec
+++ b/freed-ora/current/master/kernel.spec
@@ -62,7 +62,7 @@ Summary: The Linux kernel
# For non-released -rc kernels, this will be appended after the rcX and
# gitX tags, so a 3 here would become part of release "0.rcX.gitX.3"
#
-%global baserelease 1
+%global baserelease 2
%global fedora_build %{baserelease}
# base_sublevel is the kernel version we're starting with and patching
@@ -727,7 +727,7 @@ Patch800: crash-driver.patch
# crypto/
# secure boot
-Patch1000: secure-boot-20130218.patch
+Patch1000: devel-pekey-secure-boot-20130219.patch
# virt + ksm patches
@@ -803,9 +803,15 @@ Patch21247: ath9k_rx_dma_stop_check.patch
#rhbz 910126
Patch21249: pstore-Create-a-convenient-mount-point-for-pstore.patch
+#rhbz 844750
+Patch21250: 0001-bluetooth-Add-support-for-atheros-04ca-3004-device-t.patch
+
#rhbz 909591
Patch21255: usb-cypress-supertop.patch
+#rhbz 812111
+Patch21260: alps-v2.patch
+
Patch22000: weird-root-dentry-name-debug.patch
#selinux ptrace child permissions
@@ -1506,7 +1512,7 @@ ApplyPatch crash-driver.patch
# crypto/
# secure boot
-ApplyPatch secure-boot-20130218.patch
+ApplyPatch devel-pekey-secure-boot-20130219.patch
# Assorted Virt Fixes
@@ -1576,6 +1582,12 @@ ApplyPatch pstore-Create-a-convenient-mount-point-for-pstore.patch
#rhbz 909591
ApplyPatch usb-cypress-supertop.patch
+#rhbz 844750
+ApplyPatch 0001-bluetooth-Add-support-for-atheros-04ca-3004-device-t.patch
+
+#rhbz 812111
+ApplyPatch alps-v2.patch
+
# END OF PATCH APPLICATIONS
%endif
@@ -2442,6 +2454,12 @@ fi
# ||----w |
# || ||
%changelog
+* Tue Feb 19 2013 Josh Boyer <jwboyer@redhat.com> - 3.8.0-2
+- Add pekey support from David Howells and rework secure-boot patchset on top
+- Add support for Atheros 04ca:3004 bluetooth devices (rhbz 844750)
+- Backport support for newer ALPS touchpads (rhbz 812111)
+- Enable CONFIG_AUDIT_LOGINUID_IMMUTABLE
+
* Tue Feb 19 2013 Alexandre Oliva <lxoliva@fsfla.org> -libre
- GNU Linux-libre 3.8-gnu.
OpenPOWER on IntegriCloud