aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-07-01 11:02:51 -0400
committerDavid Howells <dhowells@redhat.com>2014-07-09 09:58:37 -0400
commit09dacbbda935895a4898e517e1248c11ca493216 (patch)
tree0860458e753285731c8f9752a95b2cbe53684c67 /crypto
parent26d1164be37f1145a96af15f294122876d8e5c77 (diff)
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> Acked-by: Vivek Goyal <vgoyal@redhat.com> Reviewed-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/asymmetric_keys/verify_pefile.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index aec7c509404e..2f5268cb843d 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -15,6 +15,7 @@
15#include <linux/slab.h> 15#include <linux/slab.h>
16#include <linux/err.h> 16#include <linux/err.h>
17#include <linux/pe.h> 17#include <linux/pe.h>
18#include <linux/asn1.h>
18#include <crypto/pkcs7.h> 19#include <crypto/pkcs7.h>
19#include <crypto/hash.h> 20#include <crypto/hash.h>
20#include "verify_pefile.h" 21#include "verify_pefile.h"
@@ -118,6 +119,72 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
118 return 0; 119 return 0;
119} 120}
120 121
122/*
123 * Check and strip the PE wrapper from around the signature and check that the
124 * remnant looks something like PKCS#7.
125 */
126static int pefile_strip_sig_wrapper(const void *pebuf,
127 struct pefile_context *ctx)
128{
129 struct win_certificate wrapper;
130 const u8 *pkcs7;
131
132 if (ctx->sig_len < sizeof(wrapper)) {
133 pr_debug("Signature wrapper too short\n");
134 return -ELIBBAD;
135 }
136
137 memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
138 pr_debug("sig wrapper = { %x, %x, %x }\n",
139 wrapper.length, wrapper.revision, wrapper.cert_type);
140
141 /* Both pesign and sbsign round up the length of certificate table
142 * (in optional header data directories) to 8 byte alignment.
143 */
144 if (round_up(wrapper.length, 8) != ctx->sig_len) {
145 pr_debug("Signature wrapper len wrong\n");
146 return -ELIBBAD;
147 }
148 if (wrapper.revision != WIN_CERT_REVISION_2_0) {
149 pr_debug("Signature is not revision 2.0\n");
150 return -ENOTSUPP;
151 }
152 if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
153 pr_debug("Signature certificate type is not PKCS\n");
154 return -ENOTSUPP;
155 }
156
157 /* Looks like actual pkcs signature length is in wrapper->length.
158 * size obtained from data dir entries lists the total size of
159 * certificate table which is also aligned to octawrod boundary.
160 *
161 * So set signature length field appropriately.
162 */
163 ctx->sig_len = wrapper.length;
164 ctx->sig_offset += sizeof(wrapper);
165 ctx->sig_len -= sizeof(wrapper);
166 if (ctx->sig_len == 0) {
167 pr_debug("Signature data missing\n");
168 return -EKEYREJECTED;
169 }
170
171 /* What's left should a PKCS#7 cert */
172 pkcs7 = pebuf + ctx->sig_offset;
173 if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) {
174 if (pkcs7[1] == 0x82 &&
175 pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) &&
176 pkcs7[3] == ((ctx->sig_len - 4) & 0xff))
177 return 0;
178 if (pkcs7[1] == 0x80)
179 return 0;
180 if (pkcs7[1] > 0x82)
181 return -EMSGSIZE;
182 }
183
184 pr_debug("Signature data not PKCS#7\n");
185 return -ELIBBAD;
186}
187
121/** 188/**
122 * verify_pefile_signature - Verify the signature on a PE binary image 189 * verify_pefile_signature - Verify the signature on a PE binary image
123 * @pebuf: Buffer containing the PE binary image 190 * @pebuf: Buffer containing the PE binary image
@@ -159,5 +226,9 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
159 if (ret < 0) 226 if (ret < 0)
160 return ret; 227 return ret;
161 228
229 ret = pefile_strip_sig_wrapper(pebuf, &ctx);
230 if (ret < 0)
231 return ret;
232
162 return -ENOANO; // Not yet complete 233 return -ENOANO; // Not yet complete
163} 234}