1 /* Parse a signed PE binary 2 * 3 * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11 12 #define pr_fmt(fmt) "PEFILE: "fmt 13 #include <linux/module.h> 14 #include <linux/kernel.h> 15 #include <linux/slab.h> 16 #include <linux/err.h> 17 #include <linux/pe.h> 18 #include <linux/asn1.h> 19 #include <crypto/pkcs7.h> 20 #include <crypto/hash.h> 21 #include "verify_pefile.h" 22 23 /* 24 * Parse a PE binary. 25 */ 26 static int pefile_parse_binary(const void *pebuf, unsigned int pelen, 27 struct pefile_context *ctx) 28 { 29 const struct mz_hdr *mz = pebuf; 30 const struct pe_hdr *pe; 31 const struct pe32_opt_hdr *pe32; 32 const struct pe32plus_opt_hdr *pe64; 33 const struct data_directory *ddir; 34 const struct data_dirent *dde; 35 const struct section_header *secs, *sec; 36 size_t cursor, datalen = pelen; 37 38 kenter(""); 39 40 #define chkaddr(base, x, s) \ 41 do { \ 42 if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \ 43 return -ELIBBAD; \ 44 } while (0) 45 46 chkaddr(0, 0, sizeof(*mz)); 47 if (mz->magic != MZ_MAGIC) 48 return -ELIBBAD; 49 cursor = sizeof(*mz); 50 51 chkaddr(cursor, mz->peaddr, sizeof(*pe)); 52 pe = pebuf + mz->peaddr; 53 if (pe->magic != PE_MAGIC) 54 return -ELIBBAD; 55 cursor = mz->peaddr + sizeof(*pe); 56 57 chkaddr(0, cursor, sizeof(pe32->magic)); 58 pe32 = pebuf + cursor; 59 pe64 = pebuf + cursor; 60 61 switch (pe32->magic) { 62 case PE_OPT_MAGIC_PE32: 63 chkaddr(0, cursor, sizeof(*pe32)); 64 ctx->image_checksum_offset = 65 (unsigned long)&pe32->csum - (unsigned long)pebuf; 66 ctx->header_size = pe32->header_size; 67 cursor += sizeof(*pe32); 68 ctx->n_data_dirents = pe32->data_dirs; 69 break; 70 71 case PE_OPT_MAGIC_PE32PLUS: 72 chkaddr(0, cursor, sizeof(*pe64)); 73 ctx->image_checksum_offset = 74 (unsigned long)&pe64->csum - (unsigned long)pebuf; 75 ctx->header_size = pe64->header_size; 76 cursor += sizeof(*pe64); 77 ctx->n_data_dirents = pe64->data_dirs; 78 break; 79 80 default: 81 pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic); 82 return -ELIBBAD; 83 } 84 85 pr_debug("checksum @ %x\n", ctx->image_checksum_offset); 86 pr_debug("header size = %x\n", ctx->header_size); 87 88 if (cursor >= ctx->header_size || ctx->header_size >= datalen) 89 return -ELIBBAD; 90 91 if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde)) 92 return -ELIBBAD; 93 94 ddir = pebuf + cursor; 95 cursor += sizeof(*dde) * ctx->n_data_dirents; 96 97 ctx->cert_dirent_offset = 98 (unsigned long)&ddir->certs - (unsigned long)pebuf; 99 ctx->certs_size = ddir->certs.size; 100 101 if (!ddir->certs.virtual_address || !ddir->certs.size) { 102 pr_debug("Unsigned PE binary\n"); 103 return -EKEYREJECTED; 104 } 105 106 chkaddr(ctx->header_size, ddir->certs.virtual_address, 107 ddir->certs.size); 108 ctx->sig_offset = ddir->certs.virtual_address; 109 ctx->sig_len = ddir->certs.size; 110 pr_debug("cert = %x @%x [%*ph]\n", 111 ctx->sig_len, ctx->sig_offset, 112 ctx->sig_len, pebuf + ctx->sig_offset); 113 114 ctx->n_sections = pe->sections; 115 if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec)) 116 return -ELIBBAD; 117 ctx->secs = secs = pebuf + cursor; 118 119 return 0; 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 */ 126 static 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 188 /** 189 * verify_pefile_signature - Verify the signature on a PE binary image 190 * @pebuf: Buffer containing the PE binary image 191 * @pelen: Length of the binary image 192 * @trust_keyring: Signing certificates to use as starting points 193 * @_trusted: Set to true if trustworth, false otherwise 194 * 195 * Validate that the certificate chain inside the PKCS#7 message inside the PE 196 * binary image intersects keys we already know and trust. 197 * 198 * Returns, in order of descending priority: 199 * 200 * (*) -ELIBBAD if the image cannot be parsed, or: 201 * 202 * (*) -EKEYREJECTED if a signature failed to match for which we have a valid 203 * key, or: 204 * 205 * (*) 0 if at least one signature chain intersects with the keys in the trust 206 * keyring, or: 207 * 208 * (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a 209 * chain. 210 * 211 * (*) -ENOKEY if we couldn't find a match for any of the signature chains in 212 * the message. 213 * 214 * May also return -ENOMEM. 215 */ 216 int verify_pefile_signature(const void *pebuf, unsigned pelen, 217 struct key *trusted_keyring, bool *_trusted) 218 { 219 struct pefile_context ctx; 220 int ret; 221 222 kenter(""); 223 224 memset(&ctx, 0, sizeof(ctx)); 225 ret = pefile_parse_binary(pebuf, pelen, &ctx); 226 if (ret < 0) 227 return ret; 228 229 ret = pefile_strip_sig_wrapper(pebuf, &ctx); 230 if (ret < 0) 231 return ret; 232 233 return -ENOANO; // Not yet complete 234 } 235