├── .gitignore ├── .gitmodules ├── COPYING ├── LICENSE.GPLv3 ├── Makefile.am ├── NEWS ├── README ├── autogen.sh ├── configure.ac ├── docs ├── Makefile.am ├── sbattach.1.in ├── sbkeysync.1.in ├── sbsiglist.1.in ├── sbsign.1.in ├── sbvarsign.1.in └── sbverify.1.in ├── src ├── Makefile.am ├── coff │ ├── external.h │ └── pe.h ├── efivars.h ├── fileio.c ├── fileio.h ├── idc.c ├── idc.h ├── image.c ├── image.h ├── libcoff.h ├── sbattach.c ├── sbkeysync.c ├── sbsiglist.c ├── sbsign.c ├── sbvarsign.c ├── sbverify.c └── verify.c └── tests ├── Makefile.am ├── cert-table-header.sh ├── detach-remove.sh ├── reattach-warning.sh ├── resign-warning.sh ├── sign-attach-verify.sh ├── sign-detach-verify.sh ├── sign-invalidattach-verify.sh ├── sign-missing-cert.sh ├── sign-missing-image.sh ├── sign-missing-key.sh ├── sign-verify-detached.sh ├── sign-verify.sh ├── test-wrapper.sh ├── test.c ├── verify-missing-cert.sh └── verify-missing-image.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | .*.d 3 | *.o 4 | AUTHORS 5 | ChangeLog 6 | INSTALL 7 | Makefile 8 | Makefile.in 9 | aclocal.m4 10 | autom4te.cache/ 11 | compile 12 | config.h 13 | config.h.in 14 | config.log 15 | config.status 16 | configure 17 | depcomp 18 | *.1 19 | install-sh 20 | missing 21 | .deps 22 | src/sbattach 23 | src/sbkeysync 24 | src/sbsiglist 25 | src/sbsign 26 | src/sbvarsign 27 | src/sbverify 28 | stamp-h1 29 | test-driver 30 | lib/ 31 | *.pem 32 | *.patch 33 | tags 34 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/ccan.git"] 2 | path = lib/ccan.git 3 | url = https://github.com/rustyrussell/ccan 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | sbsigntool - utilities for signing UEFI binaries for use with secure boot. 2 | 3 | (c) 2012 by Jeremy Kerr, Canonical Ltd. 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License as 7 | published by the Free Software Foundation; either version 3 of the 8 | License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, but 11 | is provided AS IS, WITHOUT ANY WARRANTY; without even the implied 12 | warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and 13 | NON-INFRINGEMENT. See the GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, 18 | MA 02111-1307, USA. 19 | 20 | In addition, as a special exception, the copyright holders give 21 | permission to link the code of portions of this program with the 22 | OpenSSL library under certain conditions as described in each 23 | individual source file, and distribute linked combinations including 24 | the two. 25 | 26 | You must obey the GNU General Public License in all respects for all 27 | of the code used other than OpenSSL. If you modify file(s) with this 28 | exception, you may extend this exception to your version of the 29 | file(s), but you are not obligated to do so. If you do not wish to do 30 | so, delete this exception statement from your version. If you delete 31 | this exception statement from all source files in the program, then 32 | also delete it here. 33 | -------------------------------------------------------------------------------- /LICENSE.GPLv3: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS = lib/ccan src docs tests 3 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | v0.5: 2 | sbkeysync's default efivars mountpoint has been moved to 3 | /sys/firmware/efi/efivars/. This is to match the proposed Linux kernel 4 | patch for efivarfs, which provides this sysfs node for the purpose of 5 | mounting efivarfs, and leaving the older ../vars/ interface for legacy 6 | applications. 7 | 8 | This default can be overridden using the --efivars-path option to 9 | sbkeysync. 10 | 11 | v0.1: 12 | Initial version 13 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | sbsigntool - Signing utility for UEFI secure boot 2 | 3 | Copyright (C) 2102 Jeremy Kerr 4 | 5 | Copying and distribution of this file, with or without modification, 6 | are permitted in any medium without royalty provided the copyright 7 | notice and this notice are preserved. 8 | 9 | See file ./INSTALL for building and installation instructions. 10 | 11 | Original development was done at: 12 | git://kernel.ubuntu.com/jk/sbsigntool.git 13 | 14 | The current maintained fork resides at: 15 | 16 | https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git/ 17 | 18 | And a very low volume mailing list for bugs and patches is setup at 19 | 20 | sbsigntools@groups.io 21 | 22 | Thanks to groups.io policies, non-members can post to this list, but 23 | non-member postings are moderated until released (so they won't show 24 | up immediately). The list archives are available: 25 | 26 | https://groups.io/g/sbsigntools/topics 27 | 28 | sbsigntool is free software. See the file COPYING for copying conditions. 29 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ccan_modules="talloc read_write_all build_assert array_size endian" 4 | 5 | # Add ccan upstream sources 6 | if [ ! -e lib/ccan.git/Makefile ] 7 | then 8 | git submodule init 9 | git submodule update 10 | fi 11 | 12 | # create ccan build tree 13 | if [ ! -e lib/ccan ] 14 | then 15 | lib/ccan.git/tools/create-ccan-tree \ 16 | --build-type=automake lib/ccan $ccan_modules 17 | fi 18 | 19 | # Create generatable docs from git 20 | ( 21 | echo "Authors of sbsigntool:" 22 | echo 23 | git log --format='%an' | sort -u | sed 's,^,\t,' 24 | ) > AUTHORS 25 | 26 | # Generate simple ChangeLog 27 | git log --date=short --format='%ad %t %an <%ae>%n%n * %s%n' > ChangeLog 28 | 29 | # automagic 30 | aclocal 31 | autoheader 32 | autoconf 33 | automake --add-missing -Wno-portability 34 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([sbsigntool], [0.9.4], [James.Bottomley@HansenPartnership.com]) 2 | 3 | AM_INIT_AUTOMAKE() 4 | 5 | AC_PREREQ(2.60) 6 | 7 | AC_CONFIG_HEADERS(config.h) 8 | AC_CONFIG_SRCDIR(src/sbsign.c) 9 | 10 | AM_PROG_AS 11 | AC_PROG_CC 12 | AM_PROG_CC_C_O 13 | AC_PROG_CPP 14 | AC_PROG_RANLIB 15 | AC_PROG_MKDIR_P 16 | 17 | AC_CHECK_TOOL(OBJCOPY, [objcopy]) 18 | AC_CHECK_TOOL(STRIP, [strip]) 19 | 20 | AC_CHECK_HEADER([bfd.h], [], 21 | AC_MSG_ERROR([bfd.h not found.] 22 | [bfd.h is usually distributed in a binutils development package.])) 23 | 24 | if test $cross_compiling = no; then 25 | AM_MISSING_PROG(HELP2MAN, help2man) 26 | else 27 | HELP2MAN=: 28 | fi 29 | 30 | AC_MSG_CHECKING([build system endianness]) 31 | AC_PREPROC_IFELSE( 32 | [AC_LANG_PROGRAM([[#include ]], 33 | [[#if __BYTE_ORDER != __LITTLE_ENDIAN]] 34 | [[#error]] 35 | [[#endif]])], 36 | endian=little 37 | little_endian=1 38 | big_endian=0) 39 | 40 | AC_PREPROC_IFELSE( 41 | [AC_LANG_PROGRAM([[#include ]], 42 | [[#if __BYTE_ORDER != __BIG_ENDIAN]] 43 | [[#error]] 44 | [[#endif]])], 45 | endian=big 46 | little_endian=0 47 | big_endian=1) 48 | 49 | 50 | if test x"$endian" != "xbig" -a x"$endian" != "xlittle"; then 51 | AC_MSG_ERROR([Can't determine endianness; is endian.h present?]) 52 | fi 53 | AC_MSG_RESULT($endian) 54 | AC_DEFINE_UNQUOTED(HAVE_LITTLE_ENDIAN, $little_endian, [Little-endian system]) 55 | AC_DEFINE_UNQUOTED(HAVE_BIG_ENDIAN, $big_endian, [Big-endian system]) 56 | 57 | PKG_PROG_PKG_CONFIG() 58 | PKG_CHECK_MODULES(libcrypto, libcrypto, 59 | [], 60 | AC_MSG_ERROR([libcrypto (from the OpenSSL package) is required])) 61 | 62 | PKG_CHECK_MODULES(uuid, uuid, 63 | [], 64 | AC_MSG_ERROR([libuuid (from the uuid package) is required])) 65 | 66 | dnl gnu-efi headers require extra include dirs 67 | EFI_ARCH=$(uname -m | sed 's/i.86/ia32/;s/arm.*/arm/') 68 | AM_CONDITIONAL(TEST_BINARY_FORMAT, [ test "$EFI_ARCH" = "arm" -o "$EFI_ARCH" = "aarch64" ]) 69 | 70 | ## 71 | # no consistent view of where gnu-efi should dump the efi stuff, so find it 72 | ## 73 | for path in /lib /lib64 /usr/lib /usr/lib64 /usr/lib32 /lib/efi /lib64/efi /usr/lib/efi /usr/lib64/efi /usr/lib/gnuefi /usr/lib64/gnuefi ; do 74 | if test -e $path/crt0-efi-$EFI_ARCH.o; then 75 | CRTPATH=$path 76 | fi 77 | done 78 | if test -z "$CRTPATH"; then 79 | AC_MSG_ERROR([cannot find the gnu-efi crt path]) 80 | fi 81 | 82 | EFI_CPPFLAGS="-I/usr/include/efi -I/usr/include/efi/$EFI_ARCH \ 83 | -DEFI_FUNCTION_WRAPPER" 84 | CPPFLAGS_save="$CPPFLAGS" 85 | CPPFLAGS="$CPPFLAGS $EFI_CPPFLAGS" 86 | AC_CHECK_HEADERS([efi.h], [], [], $EFI_INCLUDES) 87 | CPPFLAGS="$CPPFLAGS_save" 88 | AC_SUBST(EFI_CPPFLAGS, $EFI_CPPFLAGS) 89 | AC_SUBST(EFI_ARCH, $EFI_ARCH) 90 | AC_SUBST(CRTPATH, $CRTPATH) 91 | 92 | AC_CONFIG_FILES([Makefile src/Makefile lib/ccan/Makefile] 93 | [docs/Makefile tests/Makefile]) 94 | AC_OUTPUT 95 | -------------------------------------------------------------------------------- /docs/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | man1_MANS = sbsign.1 sbverify.1 sbattach.1 sbvarsign.1 sbsiglist.1 \ 3 | sbkeysync.1 4 | 5 | EXTRA_DIST = sbsign.1.in sbverify.1.in sbattach.1.in \ 6 | sbvarsign.1.in sbsiglist.1.in sbkeysync.1.in 7 | CLEANFILES = $(man1_MANS) 8 | 9 | $(builddir)/%.1: $(srcdir)/%.1.in $(top_builddir)/src/% 10 | $(MKDIR_P) $(@D) 11 | $(HELP2MAN) --no-info -i $< -o $@ $(top_builddir)/src/$* 12 | 13 | -------------------------------------------------------------------------------- /docs/sbattach.1.in: -------------------------------------------------------------------------------- 1 | [name] 2 | sbattach - UEFI secure boot detached signature tool 3 | -------------------------------------------------------------------------------- /docs/sbkeysync.1.in: -------------------------------------------------------------------------------- 1 | [name] 2 | sbkeysync - UEFI secure boot key synchronization tool 3 | -------------------------------------------------------------------------------- /docs/sbsiglist.1.in: -------------------------------------------------------------------------------- 1 | [name] 2 | sbsiglist - Create EFI_SIGNATURE_LIST signature databases 3 | -------------------------------------------------------------------------------- /docs/sbsign.1.in: -------------------------------------------------------------------------------- 1 | [name] 2 | sbsign - UEFI secure boot signing tool 3 | -------------------------------------------------------------------------------- /docs/sbvarsign.1.in: -------------------------------------------------------------------------------- 1 | [name] 2 | sbvarsign - UEFI authenticated variable signing tool 3 | -------------------------------------------------------------------------------- /docs/sbverify.1.in: -------------------------------------------------------------------------------- 1 | [name] 2 | sbverify - UEFI secure boot verification tool 3 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | bin_PROGRAMS = sbsign sbverify sbattach sbvarsign sbsiglist sbkeysync 3 | 4 | coff_headers = coff/external.h coff/pe.h 5 | AM_CFLAGS = -Wall -Wextra --std=gnu99 6 | 7 | common_SOURCES = idc.c idc.h image.c image.h fileio.c fileio.h \ 8 | efivars.h $(coff_headers) 9 | common_LDADD = ../lib/ccan/libccan.a $(libcrypto_LIBS) 10 | common_CFLAGS = -I$(top_srcdir)/lib/ccan/ -Werror 11 | 12 | sbsign_SOURCES = sbsign.c $(common_SOURCES) 13 | sbsign_LDADD = $(common_LDADD) 14 | sbsign_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) 15 | 16 | sbverify_SOURCES = sbverify.c $(common_SOURCES) 17 | sbverify_LDADD = $(common_LDADD) 18 | sbverify_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) 19 | 20 | sbattach_SOURCES = sbattach.c $(common_SOURCES) 21 | sbattach_LDADD = $(common_LDADD) 22 | sbattach_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) 23 | 24 | sbvarsign_SOURCES = sbvarsign.c $(common_SOURCES) 25 | sbvarsign_LDADD = $(common_LDADD) $(uuid_LIBS) 26 | sbvarsign_CPPFLAGS = $(EFI_CPPFLAGS) 27 | sbvarsign_CFLAGS = $(AM_CFLAGS) $(uuid_CFLAGS) $(common_CFLAGS) 28 | 29 | sbsiglist_SOURCES = sbsiglist.c $(common_SOURCES) 30 | sbsiglist_LDADD = $(common_LDADD) $(uuid_LIBS) 31 | sbsiglist_CPPFLAGS = $(EFI_CPPFLAGS) 32 | sbsiglist_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) 33 | 34 | sbkeysync_SOURCES = sbkeysync.c $(common_SOURCES) 35 | sbkeysync_LDADD = $(common_LDADD) $(uuid_LIBS) 36 | sbkeysync_CPPFLAGS = $(EFI_CPPFLAGS) 37 | sbkeysync_CFLAGS = $(AM_CFLAGS) $(common_CFLAGS) 38 | -------------------------------------------------------------------------------- /src/coff/external.h: -------------------------------------------------------------------------------- 1 | /* external.h -- External COFF structures 2 | 3 | Copyright 2001, 2006, 2010 Free Software Foundation, Inc. 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 3 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 18 | MA 02110-1301, USA. */ 19 | 20 | #ifndef COFF_EXTERNAL_H 21 | #define COFF_EXTERNAL_H 22 | 23 | #ifndef DO_NOT_DEFINE_FILHDR 24 | /********************** FILE HEADER **********************/ 25 | 26 | struct external_filehdr 27 | { 28 | char f_magic[2]; /* magic number */ 29 | char f_nscns[2]; /* number of sections */ 30 | char f_timdat[4]; /* time & date stamp */ 31 | char f_symptr[4]; /* file pointer to symtab */ 32 | char f_nsyms[4]; /* number of symtab entries */ 33 | char f_opthdr[2]; /* sizeof(optional hdr) */ 34 | char f_flags[2]; /* flags */ 35 | }; 36 | 37 | #define FILHDR struct external_filehdr 38 | #define FILHSZ 20 39 | #endif 40 | 41 | #ifndef DO_NOT_DEFINE_AOUTHDR 42 | /********************** AOUT "OPTIONAL HEADER" **********************/ 43 | 44 | typedef struct external_aouthdr 45 | { 46 | char magic[2]; /* type of file */ 47 | char vstamp[2]; /* version stamp */ 48 | char tsize[4]; /* text size in bytes, padded to FW bdry*/ 49 | char dsize[4]; /* initialized data " " */ 50 | char bsize[4]; /* uninitialized data " " */ 51 | char entry[4]; /* entry pt. */ 52 | char text_start[4]; /* base of text used for this file */ 53 | char data_start[4]; /* base of data used for this file */ 54 | } ATTRIBUTE_PACKED 55 | AOUTHDR; 56 | 57 | #define AOUTHDRSZ 28 58 | #define AOUTSZ 28 59 | 60 | typedef struct external_aouthdr64 61 | { 62 | char magic[2]; /* Type of file. */ 63 | char vstamp[2]; /* Version stamp. */ 64 | char tsize[4]; /* Text size in bytes, padded to FW bdry*/ 65 | char dsize[4]; /* Initialized data " ". */ 66 | char bsize[4]; /* Uninitialized data " ". */ 67 | char entry[4]; /* Entry pt. */ 68 | char text_start[4]; /* Base of text used for this file. */ 69 | } 70 | AOUTHDR64; 71 | #define AOUTHDRSZ64 24 72 | 73 | #endif /* not DO_NOT_DEFINE_AOUTHDR */ 74 | 75 | #ifndef DO_NOT_DEFINE_SCNHDR 76 | /********************** SECTION HEADER **********************/ 77 | 78 | struct external_scnhdr 79 | { 80 | char s_name[8]; /* section name */ 81 | char s_paddr[4]; /* physical address, aliased s_nlib */ 82 | char s_vaddr[4]; /* virtual address */ 83 | char s_size[4]; /* section size */ 84 | char s_scnptr[4]; /* file ptr to raw data for section */ 85 | char s_relptr[4]; /* file ptr to relocation */ 86 | char s_lnnoptr[4]; /* file ptr to line numbers */ 87 | char s_nreloc[2]; /* number of relocation entries */ 88 | char s_nlnno[2]; /* number of line number entries */ 89 | char s_flags[4]; /* flags */ 90 | }; 91 | 92 | #define SCNHDR struct external_scnhdr 93 | #define SCNHSZ 40 94 | 95 | /* Names of "special" sections. */ 96 | 97 | #define _TEXT ".text" 98 | #define _DATA ".data" 99 | #define _BSS ".bss" 100 | #define _COMMENT ".comment" 101 | #define _LIB ".lib" 102 | #endif /* not DO_NOT_DEFINE_SCNHDR */ 103 | 104 | #ifndef DO_NOT_DEFINE_LINENO 105 | 106 | /********************** LINE NUMBERS **********************/ 107 | 108 | #ifndef L_LNNO_SIZE 109 | #error L_LNNO_SIZE needs to be defined 110 | #endif 111 | 112 | /* 1 line number entry for every "breakpointable" source line in a section. 113 | Line numbers are grouped on a per function basis; first entry in a function 114 | grouping will have l_lnno = 0 and in place of physical address will be the 115 | symbol table index of the function name. */ 116 | struct external_lineno 117 | { 118 | union 119 | { 120 | char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ 121 | char l_paddr[4]; /* (physical) address of line number */ 122 | } l_addr; 123 | 124 | char l_lnno[L_LNNO_SIZE]; /* line number */ 125 | }; 126 | 127 | #define LINENO struct external_lineno 128 | #define LINESZ (4 + L_LNNO_SIZE) 129 | 130 | #if L_LNNO_SIZE == 4 131 | #define GET_LINENO_LNNO(abfd, ext) H_GET_32 (abfd, (ext->l_lnno)) 132 | #define PUT_LINENO_LNNO(abfd, val, ext) H_PUT_32 (abfd, val, (ext->l_lnno)) 133 | #endif 134 | #if L_LNNO_SIZE == 2 135 | #define GET_LINENO_LNNO(abfd, ext) H_GET_16 (abfd, (ext->l_lnno)) 136 | #define PUT_LINENO_LNNO(abfd, val, ext) H_PUT_16 (abfd, val, (ext->l_lnno)) 137 | #endif 138 | 139 | #endif /* not DO_NOT_DEFINE_LINENO */ 140 | 141 | #ifndef DO_NOT_DEFINE_SYMENT 142 | /********************** SYMBOLS **********************/ 143 | 144 | #define E_SYMNMLEN 8 /* # characters in a symbol name */ 145 | #ifndef E_FILNMLEN 146 | #define E_FILNMLEN 14 147 | #endif 148 | #define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ 149 | 150 | struct external_syment 151 | { 152 | union 153 | { 154 | char e_name[E_SYMNMLEN]; 155 | 156 | struct 157 | { 158 | char e_zeroes[4]; 159 | char e_offset[4]; 160 | } e; 161 | } e; 162 | 163 | char e_value[4]; 164 | char e_scnum[2]; 165 | char e_type[2]; 166 | char e_sclass[1]; 167 | char e_numaux[1]; 168 | } ATTRIBUTE_PACKED ; 169 | 170 | #define SYMENT struct external_syment 171 | #define SYMESZ 18 172 | 173 | #ifndef N_BTMASK 174 | #define N_BTMASK 0xf 175 | #endif 176 | 177 | #ifndef N_TMASK 178 | #define N_TMASK 0x30 179 | #endif 180 | 181 | #ifndef N_BTSHFT 182 | #define N_BTSHFT 4 183 | #endif 184 | 185 | #ifndef N_TSHIFT 186 | #define N_TSHIFT 2 187 | #endif 188 | 189 | #endif /* not DO_NOT_DEFINE_SYMENT */ 190 | 191 | #ifndef DO_NOT_DEFINE_AUXENT 192 | 193 | union external_auxent 194 | { 195 | struct 196 | { 197 | char x_tagndx[4]; /* str, un, or enum tag indx */ 198 | 199 | union 200 | { 201 | struct 202 | { 203 | char x_lnno[2]; /* declaration line number */ 204 | char x_size[2]; /* str/union/array size */ 205 | } x_lnsz; 206 | 207 | char x_fsize[4]; /* size of function */ 208 | 209 | } x_misc; 210 | 211 | union 212 | { 213 | struct /* if ISFCN, tag, or .bb */ 214 | { 215 | char x_lnnoptr[4]; /* ptr to fcn line # */ 216 | char x_endndx[4]; /* entry ndx past block end */ 217 | } x_fcn; 218 | 219 | struct /* if ISARY, up to 4 dimen. */ 220 | { 221 | char x_dimen[E_DIMNUM][2]; 222 | } x_ary; 223 | 224 | } x_fcnary; 225 | 226 | char x_tvndx[2]; /* tv index */ 227 | 228 | } x_sym; 229 | 230 | union 231 | { 232 | char x_fname[E_FILNMLEN]; 233 | 234 | struct 235 | { 236 | char x_zeroes[4]; 237 | char x_offset[4]; 238 | } x_n; 239 | 240 | } x_file; 241 | 242 | struct 243 | { 244 | char x_scnlen[4]; /* section length */ 245 | char x_nreloc[2]; /* # relocation entries */ 246 | char x_nlinno[2]; /* # line numbers */ 247 | #ifdef INCLUDE_COMDAT_FIELDS_IN_AUXENT 248 | char x_checksum[4]; /* section COMDAT checksum */ 249 | char x_associated[2]; /* COMDAT associated section index */ 250 | char x_comdat[1]; /* COMDAT selection number */ 251 | #endif 252 | } x_scn; 253 | 254 | struct 255 | { 256 | char x_tvfill[4]; /* tv fill value */ 257 | char x_tvlen[2]; /* length of .tv */ 258 | char x_tvran[2][2]; /* tv range */ 259 | } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ 260 | } ATTRIBUTE_PACKED ; 261 | 262 | #define AUXENT union external_auxent 263 | #define AUXESZ 18 264 | 265 | #define _ETEXT "etext" 266 | 267 | #endif /* not DO_NOT_DEFINE_AUXENT */ 268 | 269 | #endif /* COFF_EXTERNAL_H */ 270 | -------------------------------------------------------------------------------- /src/coff/pe.h: -------------------------------------------------------------------------------- 1 | /* pe.h - PE COFF header information 2 | 3 | Copyright 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007, 2009, 2010 4 | Free Software Foundation, Inc. 5 | 6 | This file is part of BFD, the Binary File Descriptor library. 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation; either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software Foundation, 20 | Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 21 | #ifndef _PE_H 22 | #define _PE_H 23 | 24 | /* NT specific file attributes. */ 25 | #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 26 | #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 27 | #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 28 | #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 29 | #define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 30 | #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 31 | #define IMAGE_FILE_16BIT_MACHINE 0x0040 32 | #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 33 | #define IMAGE_FILE_32BIT_MACHINE 0x0100 34 | #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 35 | #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 36 | #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 37 | #define IMAGE_FILE_SYSTEM 0x1000 38 | #define IMAGE_FILE_DLL 0x2000 39 | #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 40 | #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 41 | 42 | /* DllCharacteristics flag bits. The inconsistent naming may seem 43 | odd, but that is how they are defined in the PE specification. */ 44 | #define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040 45 | #define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080 46 | #define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100 47 | #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 48 | #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 49 | #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 50 | #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 51 | #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 52 | 53 | /* Additional flags to be set for section headers to allow the NT loader to 54 | read and write to the section data (to replace the addresses of data in 55 | dlls for one thing); also to execute the section in .text's case. */ 56 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 57 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 58 | #define IMAGE_SCN_MEM_READ 0x40000000 59 | #define IMAGE_SCN_MEM_WRITE 0x80000000 60 | 61 | /* Section characteristics added for ppc-nt. */ 62 | 63 | #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* Reserved. */ 64 | 65 | #define IMAGE_SCN_CNT_CODE 0x00000020 /* Section contains code. */ 66 | #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* Section contains initialized data. */ 67 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* Section contains uninitialized data. */ 68 | 69 | #define IMAGE_SCN_LNK_OTHER 0x00000100 /* Reserved. */ 70 | #define IMAGE_SCN_LNK_INFO 0x00000200 /* Section contains comments or some other type of information. */ 71 | #define IMAGE_SCN_LNK_REMOVE 0x00000800 /* Section contents will not become part of image. */ 72 | #define IMAGE_SCN_LNK_COMDAT 0x00001000 /* Section contents comdat. */ 73 | 74 | #define IMAGE_SCN_MEM_FARDATA 0x00008000 75 | 76 | #define IMAGE_SCN_MEM_PURGEABLE 0x00020000 77 | #define IMAGE_SCN_MEM_16BIT 0x00020000 78 | #define IMAGE_SCN_MEM_LOCKED 0x00040000 79 | #define IMAGE_SCN_MEM_PRELOAD 0x00080000 80 | 81 | /* Bit position in the s_flags field where the alignment values start. */ 82 | #define IMAGE_SCN_ALIGN_POWER_BIT_POS 20 83 | #define IMAGE_SCN_ALIGN_POWER_BIT_MASK 0x00f00000 84 | #define IMAGE_SCN_ALIGN_POWER_NUM(val) \ 85 | (((val) >> IMAGE_SCN_ALIGN_POWER_BIT_POS) - 1) 86 | #define IMAGE_SCN_ALIGN_POWER_CONST(val) \ 87 | (((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS) 88 | 89 | #define IMAGE_SCN_ALIGN_1BYTES IMAGE_SCN_ALIGN_POWER_CONST (0) 90 | #define IMAGE_SCN_ALIGN_2BYTES IMAGE_SCN_ALIGN_POWER_CONST (1) 91 | #define IMAGE_SCN_ALIGN_4BYTES IMAGE_SCN_ALIGN_POWER_CONST (2) 92 | #define IMAGE_SCN_ALIGN_8BYTES IMAGE_SCN_ALIGN_POWER_CONST (3) 93 | /* Default alignment if no others are specified. */ 94 | #define IMAGE_SCN_ALIGN_16BYTES IMAGE_SCN_ALIGN_POWER_CONST (4) 95 | #define IMAGE_SCN_ALIGN_32BYTES IMAGE_SCN_ALIGN_POWER_CONST (5) 96 | #define IMAGE_SCN_ALIGN_64BYTES IMAGE_SCN_ALIGN_POWER_CONST (6) 97 | #define IMAGE_SCN_ALIGN_128BYTES IMAGE_SCN_ALIGN_POWER_CONST (7) 98 | #define IMAGE_SCN_ALIGN_256BYTES IMAGE_SCN_ALIGN_POWER_CONST (8) 99 | #define IMAGE_SCN_ALIGN_512BYTES IMAGE_SCN_ALIGN_POWER_CONST (9) 100 | #define IMAGE_SCN_ALIGN_1024BYTES IMAGE_SCN_ALIGN_POWER_CONST (10) 101 | #define IMAGE_SCN_ALIGN_2048BYTES IMAGE_SCN_ALIGN_POWER_CONST (11) 102 | #define IMAGE_SCN_ALIGN_4096BYTES IMAGE_SCN_ALIGN_POWER_CONST (12) 103 | #define IMAGE_SCN_ALIGN_8192BYTES IMAGE_SCN_ALIGN_POWER_CONST (13) 104 | 105 | /* Encode alignment power into IMAGE_SCN_ALIGN bits of s_flags */ 106 | #define COFF_ENCODE_ALIGNMENT(SECTION, ALIGNMENT_POWER) \ 107 | ((SECTION).s_flags |= IMAGE_SCN_ALIGN_POWER_CONST ((ALIGNMENT_POWER))) 108 | 109 | #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* Section contains extended relocations. */ 110 | #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* Section is not cachable. */ 111 | #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* Section is not pageable. */ 112 | #define IMAGE_SCN_MEM_SHARED 0x10000000 /* Section is shareable. */ 113 | 114 | /* COMDAT selection codes. */ 115 | 116 | #define IMAGE_COMDAT_SELECT_NODUPLICATES (1) /* Warn if duplicates. */ 117 | #define IMAGE_COMDAT_SELECT_ANY (2) /* No warning. */ 118 | #define IMAGE_COMDAT_SELECT_SAME_SIZE (3) /* Warn if different size. */ 119 | #define IMAGE_COMDAT_SELECT_EXACT_MATCH (4) /* Warn if different. */ 120 | #define IMAGE_COMDAT_SELECT_ASSOCIATIVE (5) /* Base on other section. */ 121 | 122 | /* Machine numbers. */ 123 | 124 | #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 125 | #define IMAGE_FILE_MACHINE_ALPHA 0x0184 126 | #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 127 | #define IMAGE_FILE_MACHINE_AM33 0x01d3 128 | #define IMAGE_FILE_MACHINE_AMD64 0x8664 129 | #define IMAGE_FILE_MACHINE_ARM 0x01c0 130 | #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 131 | #define IMAGE_FILE_MACHINE_CEE 0xc0ee 132 | #define IMAGE_FILE_MACHINE_CEF 0x0cef 133 | #define IMAGE_FILE_MACHINE_EBC 0x0ebc 134 | #define IMAGE_FILE_MACHINE_I386 0x014c 135 | #define IMAGE_FILE_MACHINE_IA64 0x0200 136 | #define IMAGE_FILE_MACHINE_M32R 0x9041 137 | #define IMAGE_FILE_MACHINE_M68K 0x0268 138 | #define IMAGE_FILE_MACHINE_MIPS16 0x0266 139 | #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 140 | #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 141 | #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 142 | #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 143 | #define IMAGE_FILE_MACHINE_R10000 0x0168 144 | #define IMAGE_FILE_MACHINE_R3000 0x0162 145 | #define IMAGE_FILE_MACHINE_R4000 0x0166 146 | #define IMAGE_FILE_MACHINE_SH3 0x01a2 147 | #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 148 | #define IMAGE_FILE_MACHINE_SH3E 0x01a4 149 | #define IMAGE_FILE_MACHINE_SH4 0x01a6 150 | #define IMAGE_FILE_MACHINE_SH5 0x01a8 151 | #define IMAGE_FILE_MACHINE_THUMB 0x01c2 152 | #define IMAGE_FILE_MACHINE_TRICORE 0x0520 153 | #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 154 | #define IMAGE_FILE_MACHINE_AARCH64 0xaa64 155 | 156 | #define IMAGE_SUBSYSTEM_UNKNOWN 0 157 | #define IMAGE_SUBSYSTEM_NATIVE 1 158 | #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 159 | #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 160 | #define IMAGE_SUBSYSTEM_POSIX_CUI 7 161 | #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 162 | #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 163 | #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 164 | #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 165 | #define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13 166 | #define IMAGE_SUBSYSTEM_XBOX 14 167 | 168 | /* Magic values that are true for all dos/nt implementations. */ 169 | #define DOSMAGIC 0x5a4d 170 | #define NT_SIGNATURE 0x00004550 171 | 172 | /* NT allows long filenames, we want to accommodate this. 173 | This may break some of the bfd functions. */ 174 | #undef FILNMLEN 175 | #define FILNMLEN 18 /* # characters in a file name. */ 176 | 177 | struct external_PEI_DOS_hdr 178 | { 179 | /* DOS header fields - always at offset zero in the EXE file. */ 180 | char e_magic[2]; /* Magic number, 0x5a4d. */ 181 | char e_cblp[2]; /* Bytes on last page of file, 0x90. */ 182 | char e_cp[2]; /* Pages in file, 0x3. */ 183 | char e_crlc[2]; /* Relocations, 0x0. */ 184 | char e_cparhdr[2]; /* Size of header in paragraphs, 0x4. */ 185 | char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0. */ 186 | char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF. */ 187 | char e_ss[2]; /* Initial (relative) SS value, 0x0. */ 188 | char e_sp[2]; /* Initial SP value, 0xb8. */ 189 | char e_csum[2]; /* Checksum, 0x0. */ 190 | char e_ip[2]; /* Initial IP value, 0x0. */ 191 | char e_cs[2]; /* Initial (relative) CS value, 0x0. */ 192 | char e_lfarlc[2]; /* File address of relocation table, 0x40. */ 193 | char e_ovno[2]; /* Overlay number, 0x0. */ 194 | char e_res[4][2]; /* Reserved words, all 0x0. */ 195 | char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0. */ 196 | char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0. */ 197 | char e_res2[10][2]; /* Reserved words, all 0x0. */ 198 | char e_lfanew[4]; /* File address of new exe header, usually 0x80. */ 199 | char dos_message[16][4]; /* Other stuff, always follow DOS header. */ 200 | }; 201 | 202 | struct external_PEI_IMAGE_hdr 203 | { 204 | char nt_signature[4]; /* required NT signature, 0x4550. */ 205 | 206 | /* From standard header. */ 207 | char f_magic[2]; /* Magic number. */ 208 | char f_nscns[2]; /* Number of sections. */ 209 | char f_timdat[4]; /* Time & date stamp. */ 210 | char f_symptr[4]; /* File pointer to symtab. */ 211 | char f_nsyms[4]; /* Number of symtab entries. */ 212 | char f_opthdr[2]; /* Sizeof(optional hdr). */ 213 | char f_flags[2]; /* Flags. */ 214 | }; 215 | 216 | struct external_PEI_filehdr 217 | { 218 | /* DOS header fields - always at offset zero in the EXE file. */ 219 | char e_magic[2]; /* Magic number, 0x5a4d. */ 220 | char e_cblp[2]; /* Bytes on last page of file, 0x90. */ 221 | char e_cp[2]; /* Pages in file, 0x3. */ 222 | char e_crlc[2]; /* Relocations, 0x0. */ 223 | char e_cparhdr[2]; /* Size of header in paragraphs, 0x4. */ 224 | char e_minalloc[2]; /* Minimum extra paragraphs needed, 0x0. */ 225 | char e_maxalloc[2]; /* Maximum extra paragraphs needed, 0xFFFF. */ 226 | char e_ss[2]; /* Initial (relative) SS value, 0x0. */ 227 | char e_sp[2]; /* Initial SP value, 0xb8. */ 228 | char e_csum[2]; /* Checksum, 0x0. */ 229 | char e_ip[2]; /* Initial IP value, 0x0. */ 230 | char e_cs[2]; /* Initial (relative) CS value, 0x0. */ 231 | char e_lfarlc[2]; /* File address of relocation table, 0x40. */ 232 | char e_ovno[2]; /* Overlay number, 0x0. */ 233 | char e_res[4][2]; /* Reserved words, all 0x0. */ 234 | char e_oemid[2]; /* OEM identifier (for e_oeminfo), 0x0. */ 235 | char e_oeminfo[2]; /* OEM information; e_oemid specific, 0x0. */ 236 | char e_res2[10][2]; /* Reserved words, all 0x0. */ 237 | char e_lfanew[4]; /* File address of new exe header, usually 0x80. */ 238 | char dos_message[16][4]; /* Other stuff, always follow DOS header. */ 239 | 240 | /* Note: additional bytes may be inserted before the signature. Use 241 | the e_lfanew field to find the actual location of the NT signature. */ 242 | 243 | char nt_signature[4]; /* required NT signature, 0x4550. */ 244 | 245 | /* From standard header. */ 246 | char f_magic[2]; /* Magic number. */ 247 | char f_nscns[2]; /* Number of sections. */ 248 | char f_timdat[4]; /* Time & date stamp. */ 249 | char f_symptr[4]; /* File pointer to symtab. */ 250 | char f_nsyms[4]; /* Number of symtab entries. */ 251 | char f_opthdr[2]; /* Sizeof(optional hdr). */ 252 | char f_flags[2]; /* Flags. */ 253 | }; 254 | 255 | #ifdef COFF_IMAGE_WITH_PE 256 | 257 | /* The filehdr is only weird in images. */ 258 | 259 | #undef FILHDR 260 | #define FILHDR struct external_PEI_filehdr 261 | #undef FILHSZ 262 | #define FILHSZ 152 263 | 264 | #endif /* COFF_IMAGE_WITH_PE */ 265 | 266 | /* 32-bit PE a.out header: */ 267 | 268 | typedef struct 269 | { 270 | AOUTHDR standard; 271 | 272 | /* NT extra fields; see internal.h for descriptions. */ 273 | char ImageBase[4]; 274 | char SectionAlignment[4]; 275 | char FileAlignment[4]; 276 | char MajorOperatingSystemVersion[2]; 277 | char MinorOperatingSystemVersion[2]; 278 | char MajorImageVersion[2]; 279 | char MinorImageVersion[2]; 280 | char MajorSubsystemVersion[2]; 281 | char MinorSubsystemVersion[2]; 282 | char Reserved1[4]; 283 | char SizeOfImage[4]; 284 | char SizeOfHeaders[4]; 285 | char CheckSum[4]; 286 | char Subsystem[2]; 287 | char DllCharacteristics[2]; 288 | char SizeOfStackReserve[4]; 289 | char SizeOfStackCommit[4]; 290 | char SizeOfHeapReserve[4]; 291 | char SizeOfHeapCommit[4]; 292 | char LoaderFlags[4]; 293 | char NumberOfRvaAndSizes[4]; 294 | /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ 295 | char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */ 296 | } PEAOUTHDR; 297 | 298 | #undef AOUTSZ 299 | #define AOUTSZ (AOUTHDRSZ + 196) 300 | 301 | /* Like PEAOUTHDR, except that the "standard" member has no BaseOfData 302 | (aka data_start) member and that some of the members are 8 instead 303 | of just 4 bytes long. */ 304 | typedef struct 305 | { 306 | #ifdef AOUTHDRSZ64 307 | AOUTHDR64 standard; 308 | #else 309 | AOUTHDR standard; 310 | #endif 311 | /* NT extra fields; see internal.h for descriptions. */ 312 | char ImageBase[8]; 313 | char SectionAlignment[4]; 314 | char FileAlignment[4]; 315 | char MajorOperatingSystemVersion[2]; 316 | char MinorOperatingSystemVersion[2]; 317 | char MajorImageVersion[2]; 318 | char MinorImageVersion[2]; 319 | char MajorSubsystemVersion[2]; 320 | char MinorSubsystemVersion[2]; 321 | char Reserved1[4]; 322 | char SizeOfImage[4]; 323 | char SizeOfHeaders[4]; 324 | char CheckSum[4]; 325 | char Subsystem[2]; 326 | char DllCharacteristics[2]; 327 | char SizeOfStackReserve[8]; 328 | char SizeOfStackCommit[8]; 329 | char SizeOfHeapReserve[8]; 330 | char SizeOfHeapCommit[8]; 331 | char LoaderFlags[4]; 332 | char NumberOfRvaAndSizes[4]; 333 | /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */ 334 | char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars. */ 335 | } PEPAOUTHDR; 336 | 337 | #ifdef AOUTHDRSZ64 338 | #define PEPAOUTSZ (AOUTHDRSZ64 + 196 + 5 * 4) /* = 240 */ 339 | #else 340 | #define PEPAOUTSZ 240 341 | #endif 342 | 343 | #undef E_FILNMLEN 344 | #define E_FILNMLEN 18 /* # characters in a file name. */ 345 | 346 | /* Import Tyoes fot ILF format object files.. */ 347 | #define IMPORT_CODE 0 348 | #define IMPORT_DATA 1 349 | #define IMPORT_CONST 2 350 | 351 | /* Import Name Tyoes for ILF format object files. */ 352 | #define IMPORT_ORDINAL 0 353 | #define IMPORT_NAME 1 354 | #define IMPORT_NAME_NOPREFIX 2 355 | #define IMPORT_NAME_UNDECORATE 3 356 | 357 | /* Weak external characteristics. */ 358 | #define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1 359 | #define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2 360 | #define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3 361 | 362 | /* .pdata/.xdata defines and structures for x64 PE+ for exception handling. */ 363 | 364 | /* .pdata in exception directory. */ 365 | 366 | struct pex64_runtime_function 367 | { 368 | bfd_vma rva_BeginAddress; 369 | bfd_vma rva_EndAddress; 370 | bfd_vma rva_UnwindData; 371 | unsigned int isChained : 1; 372 | }; 373 | 374 | struct external_pex64_runtime_function 375 | { 376 | bfd_byte rva_BeginAddress[4]; 377 | bfd_byte rva_EndAddress[4]; 378 | bfd_byte rva_UnwindData[4]; 379 | }; 380 | 381 | /* If the lowest significant bit is set for rva_UnwindData RVA, it 382 | means that the unified RVA points to another pex64_runtime_function 383 | that this entry shares the unwind_info block with. */ 384 | #define PEX64_IS_RUNTIME_FUNCTION_CHAINED(PTR_RTF) \ 385 | (((PTR_RTF)->rva_UnwindData & 1) != 0) 386 | #define PEX64_GET_UNWINDDATA_UNIFIED_RVA(PTR_RTF) \ 387 | ((PTR_RTF)->rva_UnwindData & ~1) 388 | 389 | /* The unwind codes. */ 390 | #define UWOP_PUSH_NONVOL 0 391 | #define UWOP_ALLOC_LARGE 1 392 | #define UWOP_ALLOC_SMALL 2 393 | #define UWOP_SET_FPREG 3 394 | #define UWOP_SAVE_NONVOL 4 395 | #define UWOP_SAVE_NONVOL_FAR 5 396 | #define UWOP_SAVE_XMM 6 397 | #define UWOP_SAVE_XMM_FAR 7 398 | #define UWOP_SAVE_XMM128 8 399 | #define UWOP_SAVE_XMM128_FAR 9 400 | #define UWOP_PUSH_MACHFRAME 10 401 | 402 | struct pex64_unwind_code 403 | { 404 | bfd_vma prologue_offset; 405 | /* Contains Frame offset, or frame allocation size. */ 406 | bfd_vma frame_addr; 407 | unsigned int uwop_code : 4; 408 | /* xmm, mm, or standard register from 0 - 15. */ 409 | unsigned int reg : 4; 410 | /* Used for UWOP_PUSH_MACHFRAME to indicate optional errorcode stack 411 | argument. */ 412 | unsigned int has_errorcode : 1; 413 | }; 414 | 415 | struct external_pex64_unwind_code 416 | { 417 | bfd_byte dta[2]; 418 | }; 419 | 420 | #define PEX64_UNWCODE_CODE(VAL) ((VAL) & 0xf) 421 | #define PEX64_UNWCODE_INFO(VAL) (((VAL) >> 4) & 0xf) 422 | 423 | /* The unwind info. */ 424 | #define UNW_FLAG_NHANDLER 0 425 | #define UNW_FLAG_EHANDLER 1 426 | #define UNW_FLAG_UHANDLER 2 427 | #define UNW_FLAG_FHANDLER 3 428 | #define UNW_FLAG_CHAININFO 4 429 | 430 | #define UNW_FLAG_MASK 0x1f 431 | 432 | struct pex64_unwind_info 433 | { 434 | bfd_vma SizeOfBlock; 435 | bfd_byte Version; /* Values from 0 up to 7 are possible. */ 436 | bfd_byte Flags; /* Values from 0 up to 31 are possible. */ 437 | bfd_vma SizeOfPrologue; 438 | bfd_vma CountOfCodes; /* Amount of pex64_unwind_code elements. */ 439 | /* 0 = CFA, 1..15 are index of integer registers. */ 440 | unsigned int FrameRegister : 4; 441 | bfd_vma FrameOffset; 442 | bfd_vma sizeofUnwindCodes; 443 | bfd_byte *rawUnwindCodes; 444 | /* Valid for UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER. */ 445 | bfd_vma CountOfScopes; 446 | bfd_byte *rawScopeEntries; 447 | bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER. */ 448 | bfd_vma rva_TerminationHandler; /* UNW_FLAG_UHANDLER. */ 449 | bfd_vma rva_FrameHandler; /* UNW_FLAG_FHANDLER. */ 450 | bfd_vma FrameHandlerArgument; /* UNW_FLAG_FHANDLER. */ 451 | bfd_vma rva_FunctionEntry; /* UNW_FLAG_CHAININFO. */ 452 | }; 453 | 454 | struct external_pex64_unwind_info 455 | { 456 | bfd_byte Version_Flags; 457 | bfd_byte SizeOfPrologue; 458 | bfd_byte CountOfCodes; 459 | bfd_byte FrameRegisterOffset; 460 | /* external_pex64_unwind_code array. */ 461 | /* bfd_byte handler[4]; */ 462 | /* Optional language specific data. */ 463 | }; 464 | 465 | struct external_pex64_scope 466 | { 467 | bfd_vma Count; 468 | }; 469 | 470 | struct pex64_scope 471 | { 472 | bfd_byte Count[4]; 473 | }; 474 | 475 | struct pex64_scope_entry 476 | { 477 | bfd_vma rva_BeginAddress; 478 | bfd_vma rva_EndAddress; 479 | bfd_vma rva_HandlerAddress; 480 | bfd_vma rva_JumpAddress; 481 | }; 482 | #define PEX64_SCOPE_ENTRY_SIZE 16 483 | 484 | struct external_pex64_scope_entry 485 | { 486 | bfd_byte rva_BeginAddress[4]; 487 | bfd_byte rva_EndAddress[4]; 488 | bfd_byte rva_HandlerAddress[4]; 489 | bfd_byte rva_JumpAddress[4]; 490 | }; 491 | 492 | #define PEX64_UWI_VERSION(VAL) ((VAL) & 7) 493 | #define PEX64_UWI_FLAGS(VAL) (((VAL) >> 3) & 0x1f) 494 | #define PEX64_UWI_FRAMEREG(VAL) ((VAL) & 0xf) 495 | #define PEX64_UWI_FRAMEOFF(VAL) (((VAL) >> 4) & 0xf) 496 | #define PEX64_UWI_SIZEOF_UWCODE_ARRAY(VAL) \ 497 | ((((VAL) + 1) & ~1) * 2) 498 | 499 | #define PEX64_OFFSET_TO_UNWIND_CODE 0x4 500 | 501 | #define PEX64_OFFSET_TO_HANDLER_RVA (COUNTOFUNWINDCODES) \ 502 | (PEX64_OFFSET_TO_UNWIND_CODE + \ 503 | PEX64_UWI_SIZEOF_UWCODE_ARRAY(COUNTOFUNWINDCODES)) 504 | 505 | #define PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) \ 506 | (PEX64_OFFSET_TO_HANDLER_RVA(COUNTOFUNWINDCODES) + 4) 507 | 508 | #define PEX64_SCOPE_ENTRY(COUNTOFUNWINDCODES, IDX) \ 509 | (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \ 510 | PEX64_SCOPE_ENTRY_SIZE * (IDX)) 511 | 512 | #endif /* _PE_H */ 513 | -------------------------------------------------------------------------------- /src/efivars.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #ifndef EFI_VARAUTH_H 33 | #define EFI_VARAUTH_H 34 | 35 | #include 36 | 37 | #define EFI_CERT_TYPE_PKCS7_GUID \ 38 | { 0x4aafd29d, 0x68df, 0x49ee, \ 39 | { 0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7 } } 40 | 41 | #define EFI_CERT_X509_GUID \ 42 | { 0xa5c059a1, 0x94e4, 0x4aa7, \ 43 | { 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 } } 44 | 45 | #define EFI_CERT_SHA256_GUID \ 46 | { 0xc1c41626, 0x504c, 0x4092, \ 47 | { 0xac, 0xa9, 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28 } } 48 | 49 | #define EFI_IMAGE_SECURITY_DATABASE_GUID \ 50 | { 0xd719b2cb, 0x3d3a, 0x4596, \ 51 | { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f } } 52 | 53 | 54 | #ifndef EFI_VARIABLE_NON_VOLATILE 55 | #define EFI_VARIABLE_NON_VOLATILE 0x00000001 56 | #endif 57 | 58 | #ifndef EFI_VARIABLE_BOOTSERVICE_ACCESS 59 | #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 60 | #endif 61 | 62 | #ifndef EFI_VARIABLE_RUNTIME_ACCESS 63 | #define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 64 | #endif 65 | 66 | #ifndef EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 67 | #define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 68 | #endif 69 | 70 | #ifndef EFI_VARIABLE_APPEND_WRITE 71 | #define EFI_VARIABLE_APPEND_WRITE 0x00000040 72 | #endif 73 | 74 | typedef struct { 75 | UINT32 dwLength; 76 | UINT16 wRevision; 77 | UINT16 wCertificateType; 78 | UINT8 bCertificate[]; 79 | } WIN_CERTIFICATE; 80 | 81 | typedef struct { 82 | WIN_CERTIFICATE Hdr; 83 | EFI_GUID CertType; 84 | UINT8 CertData[]; 85 | } WIN_CERTIFICATE_UEFI_GUID; 86 | 87 | typedef struct { 88 | EFI_TIME TimeStamp; 89 | WIN_CERTIFICATE_UEFI_GUID AuthInfo; 90 | } EFI_VARIABLE_AUTHENTICATION_2; 91 | 92 | 93 | typedef struct { 94 | EFI_GUID SignatureOwner; 95 | UINT8 SignatureData[]; 96 | } EFI_SIGNATURE_DATA; 97 | 98 | typedef struct { 99 | EFI_GUID SignatureType; 100 | UINT32 SignatureListSize; 101 | UINT32 SignatureHeaderSize; 102 | UINT32 SignatureSize; 103 | } EFI_SIGNATURE_LIST; 104 | 105 | #endif /* EFI_VARAUTH_H */ 106 | 107 | -------------------------------------------------------------------------------- /src/fileio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include "fileio.h" 48 | 49 | #define FLAG_NOERROR (1<<0) 50 | 51 | static int ui_read(UI *ui, UI_STRING *uis) 52 | { 53 | char password[128]; 54 | 55 | if (UI_get_string_type(uis) != UIT_PROMPT) 56 | return 0; 57 | 58 | EVP_read_pw_string(password, sizeof(password), "Enter engine key pass phrase:", 0); 59 | UI_set_result(ui, uis, password); 60 | return 1; 61 | } 62 | 63 | EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename) 64 | { 65 | UI_METHOD *ui; 66 | ENGINE *e; 67 | EVP_PKEY *pkey = NULL; 68 | 69 | ENGINE_load_builtin_engines(); 70 | e = ENGINE_by_id(engine); 71 | 72 | if (!e) { 73 | fprintf(stderr, "Failed to load engine: %s\n", engine); 74 | ERR_print_errors_fp(stderr); 75 | return NULL; 76 | } 77 | 78 | ui = UI_create_method("sbsigntools"); 79 | if (!ui) { 80 | fprintf(stderr, "Failed to create UI method\n"); 81 | ERR_print_errors_fp(stderr); 82 | goto out_free; 83 | } 84 | UI_method_set_reader(ui, ui_read); 85 | 86 | if (!ENGINE_init(e)) { 87 | fprintf(stderr, "Failed to initialize engine %s\n", engine); 88 | ERR_print_errors_fp(stderr); 89 | goto out_free; 90 | } 91 | 92 | pkey = ENGINE_load_private_key(e, filename, ui, NULL); 93 | //ENGINE_finish(e); 94 | 95 | out_free: 96 | ENGINE_free(e); 97 | return pkey; 98 | } 99 | 100 | EVP_PKEY *fileio_read_pkey(const char *filename) 101 | { 102 | EVP_PKEY *key = NULL; 103 | BIO *bio; 104 | 105 | bio = BIO_new_file(filename, "r"); 106 | if (!bio) 107 | goto out; 108 | 109 | key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); 110 | 111 | out: 112 | BIO_free_all(bio); 113 | if (!key) { 114 | fprintf(stderr, "Can't load key from file '%s'\n", filename); 115 | ERR_print_errors_fp(stderr); 116 | } 117 | return key; 118 | } 119 | 120 | X509 *fileio_read_cert(const char *filename) 121 | { 122 | X509 *cert = NULL; 123 | BIO *bio; 124 | 125 | bio = BIO_new_file(filename, "r"); 126 | if (!bio) 127 | goto out; 128 | 129 | cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); 130 | 131 | out: 132 | BIO_free_all(bio); 133 | if (!cert) { 134 | fprintf(stderr, "Can't load certificate from file '%s'\n", 135 | filename); 136 | ERR_print_errors_fp(stderr); 137 | } 138 | return cert; 139 | } 140 | 141 | static int __fileio_read_file(void *ctx, const char *filename, 142 | uint8_t **out_buf, size_t *out_len, int flags) 143 | { 144 | struct stat statbuf; 145 | uint8_t *buf; 146 | size_t len; 147 | int fd, rc; 148 | 149 | rc = -1; 150 | 151 | fd = open(filename, O_RDONLY); 152 | if (fd < 0) 153 | goto out; 154 | 155 | rc = fstat(fd, &statbuf); 156 | if (rc) 157 | goto out; 158 | 159 | len = statbuf.st_size; 160 | 161 | buf = talloc_array(ctx, uint8_t, len); 162 | if (!buf) 163 | goto out; 164 | 165 | if (!read_all(fd, buf, len)) 166 | goto out; 167 | 168 | rc = 0; 169 | 170 | out: 171 | if (fd >= 0) 172 | close(fd); 173 | if (rc) { 174 | if (!(flags & FLAG_NOERROR)) 175 | fprintf(stderr, "Error reading file %s: %s\n", 176 | filename, strerror(errno)); 177 | } else { 178 | *out_buf = buf; 179 | *out_len = len; 180 | } 181 | return rc; 182 | 183 | } 184 | 185 | int fileio_read_file(void *ctx, const char *filename, 186 | uint8_t **out_buf, size_t *out_len) 187 | { 188 | return __fileio_read_file(ctx, filename, out_buf, out_len, 0); 189 | } 190 | 191 | int fileio_read_file_noerror(void *ctx, const char *filename, 192 | uint8_t **out_buf, size_t *out_len) 193 | { 194 | return __fileio_read_file(ctx, filename, out_buf, out_len, 195 | FLAG_NOERROR); 196 | } 197 | 198 | int fileio_write_file(const char *filename, uint8_t *buf, size_t len) 199 | { 200 | int fd; 201 | 202 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); 203 | if (fd < 0) { 204 | perror("open"); 205 | return -1; 206 | } 207 | 208 | if (!write_all(fd, buf, len)) { 209 | perror("write_all"); 210 | close(fd); 211 | return -1; 212 | } 213 | 214 | close(fd); 215 | return 0; 216 | } 217 | -------------------------------------------------------------------------------- /src/fileio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #ifndef FILEIO_H 33 | #define FILEIO_H 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | 40 | EVP_PKEY *fileio_read_pkey(const char *filename); 41 | EVP_PKEY *fileio_read_engine_key(const char *engine, const char *filename); 42 | X509 *fileio_read_cert(const char *filename); 43 | 44 | int fileio_read_file(void *ctx, const char *filename, 45 | uint8_t **out_buf, size_t *out_len); 46 | int fileio_read_file_noerror(void *ctx, const char *filename, 47 | uint8_t **out_buf, size_t *out_len); 48 | int fileio_write_file(const char *filename, uint8_t *buf, size_t len); 49 | 50 | #endif /* FILEIO_H */ 51 | 52 | -------------------------------------------------------------------------------- /src/idc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include "idc.h" 43 | 44 | typedef struct idc_type_value { 45 | ASN1_OBJECT *type; 46 | ASN1_TYPE *value; 47 | } IDC_TYPE_VALUE; 48 | 49 | ASN1_SEQUENCE(IDC_TYPE_VALUE) = { 50 | ASN1_SIMPLE(IDC_TYPE_VALUE, type, ASN1_OBJECT), 51 | ASN1_OPT(IDC_TYPE_VALUE, value, ASN1_ANY), 52 | } ASN1_SEQUENCE_END(IDC_TYPE_VALUE); 53 | 54 | IMPLEMENT_ASN1_FUNCTIONS(IDC_TYPE_VALUE); 55 | 56 | typedef struct idc_string { 57 | int type; 58 | union { 59 | ASN1_BMPSTRING *unicode; 60 | ASN1_IA5STRING *ascii; 61 | } value; 62 | } IDC_STRING; 63 | 64 | ASN1_CHOICE(IDC_STRING) = { 65 | ASN1_IMP(IDC_STRING, value.unicode, ASN1_BMPSTRING, 0), 66 | ASN1_IMP(IDC_STRING, value.ascii, ASN1_IA5STRING, 1), 67 | } ASN1_CHOICE_END(IDC_STRING); 68 | 69 | IMPLEMENT_ASN1_FUNCTIONS(IDC_STRING); 70 | 71 | typedef struct idc_link { 72 | int type; 73 | union { 74 | ASN1_NULL *url; 75 | ASN1_NULL *moniker; 76 | IDC_STRING *file; 77 | } value; 78 | } IDC_LINK; 79 | 80 | ASN1_CHOICE(IDC_LINK) = { 81 | ASN1_IMP(IDC_LINK, value.url, ASN1_NULL, 0), 82 | ASN1_IMP(IDC_LINK, value.moniker, ASN1_NULL, 1), 83 | ASN1_EXP(IDC_LINK, value.file, IDC_STRING, 2), 84 | } ASN1_CHOICE_END(IDC_LINK); 85 | 86 | IMPLEMENT_ASN1_FUNCTIONS(IDC_LINK); 87 | 88 | typedef struct idc_pe_image_data { 89 | ASN1_BIT_STRING *flags; 90 | IDC_LINK *file; 91 | } IDC_PEID; 92 | 93 | ASN1_SEQUENCE(IDC_PEID) = { 94 | ASN1_SIMPLE(IDC_PEID, flags, ASN1_BIT_STRING), 95 | ASN1_EXP(IDC_PEID, file, IDC_LINK, 0), 96 | } ASN1_SEQUENCE_END(IDC_PEID); 97 | 98 | IMPLEMENT_ASN1_FUNCTIONS(IDC_PEID); 99 | 100 | typedef struct idc_digest { 101 | X509_ALGOR *alg; 102 | ASN1_OCTET_STRING *digest; 103 | } IDC_DIGEST; 104 | 105 | ASN1_SEQUENCE(IDC_DIGEST) = { 106 | ASN1_SIMPLE(IDC_DIGEST, alg, X509_ALGOR), 107 | ASN1_SIMPLE(IDC_DIGEST, digest, ASN1_OCTET_STRING), 108 | } ASN1_SEQUENCE_END(IDC_DIGEST) 109 | 110 | IMPLEMENT_ASN1_FUNCTIONS(IDC_DIGEST) 111 | 112 | typedef struct idc { 113 | IDC_TYPE_VALUE *data; 114 | IDC_DIGEST *digest; 115 | } IDC; 116 | 117 | ASN1_SEQUENCE(IDC) = { 118 | ASN1_SIMPLE(IDC, data, IDC_TYPE_VALUE), 119 | ASN1_SIMPLE(IDC, digest, IDC_DIGEST), 120 | } ASN1_SEQUENCE_END(IDC) 121 | 122 | IMPLEMENT_ASN1_FUNCTIONS(IDC) 123 | 124 | static int type_set_sequence(void *ctx, ASN1_TYPE *type, 125 | void *s, const ASN1_ITEM *it) 126 | { 127 | uint8_t *seq_data, *tmp; 128 | ASN1_OCTET_STRING *os; 129 | ASN1_STRING *seq = s; 130 | int len; 131 | 132 | os = ASN1_STRING_new(); 133 | 134 | len = ASN1_item_i2d((ASN1_VALUE *)seq, NULL, it); 135 | tmp = seq_data = talloc_array(ctx, uint8_t, len); 136 | ASN1_item_i2d((ASN1_VALUE *)seq, &tmp, it); 137 | 138 | ASN1_STRING_set(os, seq_data, len); 139 | ASN1_TYPE_set(type, V_ASN1_SEQUENCE, os); 140 | return 0; 141 | } 142 | 143 | const char obsolete[] = { 144 | 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62, 145 | 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 146 | 0x00, 0x65, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e 147 | }; 148 | 149 | const char *sha256_str(const uint8_t *hash) 150 | { 151 | static char s[SHA256_DIGEST_LENGTH * 2 + 1]; 152 | int i; 153 | 154 | for (i = 0; i < SHA256_DIGEST_LENGTH; i++) 155 | snprintf(s + i * 2, 3, "%02x", hash[i]); 156 | 157 | return s; 158 | } 159 | 160 | int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image) 161 | { 162 | uint8_t *buf, *tmp, sha[SHA256_DIGEST_LENGTH]; 163 | int idc_nid, peid_nid, len, rc; 164 | IDC_PEID *peid; 165 | ASN1_STRING *s; 166 | ASN1_TYPE *t; 167 | BIO *sigbio; 168 | IDC *idc; 169 | 170 | idc_nid = OBJ_create("1.3.6.1.4.1.311.2.1.4", 171 | "spcIndirectDataContext", 172 | "Indirect Data Context"); 173 | peid_nid = OBJ_create("1.3.6.1.4.1.311.2.1.15", 174 | "spcPEImageData", 175 | "PE Image Data"); 176 | 177 | image_hash_sha256(image, sha); 178 | 179 | idc = IDC_new(); 180 | peid = IDC_PEID_new(); 181 | 182 | peid->file = IDC_LINK_new(); 183 | peid->file->type = 2; 184 | peid->file->value.file = IDC_STRING_new(); 185 | peid->file->value.file->type = 0; 186 | peid->file->value.file->value.unicode = ASN1_STRING_new(); 187 | ASN1_STRING_set(peid->file->value.file->value.unicode, 188 | obsolete, sizeof(obsolete)); 189 | 190 | idc->data->type = OBJ_nid2obj(peid_nid); 191 | idc->data->value = ASN1_TYPE_new(); 192 | type_set_sequence(image, idc->data->value, peid, &IDC_PEID_it); 193 | 194 | idc->digest->alg->parameter = ASN1_TYPE_new(); 195 | idc->digest->alg->algorithm = OBJ_nid2obj(NID_sha256); 196 | idc->digest->alg->parameter->type = V_ASN1_NULL; 197 | ASN1_OCTET_STRING_set(idc->digest->digest, sha, sizeof(sha)); 198 | 199 | len = i2d_IDC(idc, NULL); 200 | tmp = buf = talloc_array(image, uint8_t, len); 201 | i2d_IDC(idc, &tmp); 202 | 203 | /* Add the contentType authenticated attribute */ 204 | PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, 205 | OBJ_nid2obj(idc_nid)); 206 | 207 | /* Because the PKCS7 lib has a hard time dealing with non-standard 208 | * data types, we create a temporary BIO to hold the signed data, so 209 | * that the top-level PKCS7 object calculates the correct hash... 210 | */ 211 | sigbio = PKCS7_dataInit(p7, NULL); 212 | BIO_write(sigbio, buf+2, len-2); 213 | 214 | /* ... then we finalise the p7 content, which does the actual 215 | * signing ... */ 216 | rc = PKCS7_dataFinal(p7, sigbio); 217 | if (!rc) { 218 | fprintf(stderr, "dataFinal failed\n"); 219 | ERR_print_errors_fp(stderr); 220 | return -1; 221 | } 222 | 223 | /* ... and we replace the content with the actual IDC ASN type. */ 224 | t = ASN1_TYPE_new(); 225 | s = ASN1_STRING_new(); 226 | ASN1_STRING_set(s, buf, len); 227 | ASN1_TYPE_set(t, V_ASN1_SEQUENCE, s); 228 | PKCS7_set0_type_other(p7->d.sign->contents, idc_nid, t); 229 | 230 | return 0; 231 | } 232 | 233 | struct idc *IDC_get(PKCS7 *p7, BIO *bio) 234 | { 235 | const unsigned char *buf, *idcbuf; 236 | ASN1_STRING *str; 237 | IDC *idc; 238 | 239 | /* extract the idc from the signed PKCS7 'other' data */ 240 | str = p7->d.sign->contents->d.other->value.asn1_string; 241 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 242 | idcbuf = buf = ASN1_STRING_data(str); 243 | #else 244 | idcbuf = buf = ASN1_STRING_get0_data(str); 245 | #endif 246 | idc = d2i_IDC(NULL, &buf, ASN1_STRING_length(str)); 247 | 248 | /* If we were passed a BIO, write the idc data, minus type and length, 249 | * to the BIO. This can be used to PKCS7_verify the idc */ 250 | if (bio) { 251 | uint32_t idclen; 252 | uint8_t tmp; 253 | 254 | tmp = idcbuf[1]; 255 | 256 | if (!(tmp & 0x80)) { 257 | idclen = tmp & 0x7f; 258 | idcbuf += 2; 259 | } else if ((tmp & 0x82) == 0x82) { 260 | idclen = (idcbuf[2] << 8) + 261 | idcbuf[3]; 262 | idcbuf += 4; 263 | } else { 264 | fprintf(stderr, "Invalid ASN.1 data in " 265 | "IndirectDataContext?\n"); 266 | return NULL; 267 | } 268 | 269 | BIO_write(bio, idcbuf, idclen); 270 | } 271 | 272 | return idc; 273 | } 274 | 275 | int IDC_check_hash(struct idc *idc, struct image *image) 276 | { 277 | unsigned char sha[SHA256_DIGEST_LENGTH]; 278 | const unsigned char *buf; 279 | ASN1_STRING *str; 280 | 281 | image_hash_sha256(image, sha); 282 | 283 | /* check hash algorithm sanity */ 284 | if (OBJ_cmp(idc->digest->alg->algorithm, OBJ_nid2obj(NID_sha256))) { 285 | fprintf(stderr, "Invalid algorithm type\n"); 286 | return -1; 287 | } 288 | 289 | str = idc->digest->digest; 290 | if (ASN1_STRING_length(str) != sizeof(sha)) { 291 | fprintf(stderr, "Invalid algorithm length\n"); 292 | return -1; 293 | } 294 | 295 | /* check hash against the one we calculated from the image */ 296 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 297 | buf = ASN1_STRING_data(str); 298 | #else 299 | buf = ASN1_STRING_get0_data(str); 300 | #endif 301 | if (memcmp(buf, sha, sizeof(sha))) { 302 | fprintf(stderr, "Hash doesn't match image\n"); 303 | fprintf(stderr, " got: %s\n", sha256_str(buf)); 304 | fprintf(stderr, " expecting: %s\n", sha256_str(sha)); 305 | return -1; 306 | } 307 | 308 | return 0; 309 | } 310 | -------------------------------------------------------------------------------- /src/idc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #ifndef IDC_H 33 | #define IDC_H 34 | 35 | #include "image.h" 36 | 37 | #include 38 | 39 | struct idc; 40 | 41 | int IDC_set(PKCS7 *p7, PKCS7_SIGNER_INFO *si, struct image *image); 42 | struct idc *IDC_get(PKCS7 *p7, BIO *bio); 43 | int IDC_check_hash(struct idc *idc, struct image *image); 44 | 45 | const char *sha256_str(const uint8_t *hash); 46 | 47 | #endif /* IDC_H */ 48 | 49 | -------------------------------------------------------------------------------- /src/image.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "fileio.h" 48 | #include "image.h" 49 | 50 | #define DATA_DIR_CERT_TABLE 4 51 | 52 | #define CERT_TABLE_TYPE_PKCS 0x0002 /* PKCS signedData */ 53 | #define CERT_TABLE_REVISION 0x0200 /* revision 2 */ 54 | 55 | /** 56 | * The PE/COFF headers export struct fields as arrays of chars. So, define 57 | * a couple of accessor functions that allow fields to be deferenced as their 58 | * native types, to allow strict aliasing. This also allows for endian- 59 | * neutral behaviour. 60 | */ 61 | static uint32_t __pehdr_u32(char field[]) 62 | { 63 | uint8_t *ufield = (uint8_t *)field; 64 | return (ufield[3] << 24) + 65 | (ufield[2] << 16) + 66 | (ufield[1] << 8) + 67 | ufield[0]; 68 | } 69 | 70 | static uint16_t __pehdr_u16(char field[]) 71 | { 72 | uint8_t *ufield = (uint8_t *)field; 73 | return (ufield[1] << 8) + 74 | ufield[0]; 75 | } 76 | 77 | /* wrappers to ensure type correctness */ 78 | #define pehdr_u32(f) __pehdr_u32(f + BUILD_ASSERT_OR_ZERO(sizeof(f) == 4)) 79 | #define pehdr_u16(f) __pehdr_u16(f + BUILD_ASSERT_OR_ZERO(sizeof(f) == 2)) 80 | 81 | /* Machine-specific PE/COFF parse functions. These parse the relevant a.out 82 | * header for the machine type, and set the following members of struct image: 83 | * - aouthdr_size 84 | * - file_alignment 85 | * - header_size 86 | * - data_dir 87 | * - checksum 88 | * 89 | * These functions require image->opthdr to be set by the caller. 90 | */ 91 | static int image_pecoff_parse_32(struct image *image) 92 | { 93 | if (image->opthdr.opt_32->standard.magic[0] != 0x0b || 94 | image->opthdr.opt_32->standard.magic[1] != 0x01) { 95 | fprintf(stderr, "Invalid a.out machine type\n"); 96 | return -1; 97 | } 98 | 99 | image->opthdr_min_size = sizeof(*image->opthdr.opt_32) - 100 | sizeof(image->opthdr.opt_32->DataDirectory); 101 | 102 | image->file_alignment = 103 | pehdr_u32(image->opthdr.opt_32->FileAlignment); 104 | image->header_size = 105 | pehdr_u32(image->opthdr.opt_32->SizeOfHeaders); 106 | 107 | image->data_dir = (void *)image->opthdr.opt_32->DataDirectory; 108 | image->checksum = (uint32_t *)image->opthdr.opt_32->CheckSum; 109 | return 0; 110 | } 111 | 112 | static int image_pecoff_parse_64(struct image *image) 113 | { 114 | if (image->opthdr.opt_64->standard.magic[0] != 0x0b || 115 | image->opthdr.opt_64->standard.magic[1] != 0x02) { 116 | fprintf(stderr, "Invalid a.out machine type\n"); 117 | return -1; 118 | } 119 | 120 | image->opthdr_min_size = sizeof(*image->opthdr.opt_64) - 121 | sizeof(image->opthdr.opt_64->DataDirectory); 122 | 123 | image->file_alignment = 124 | pehdr_u32(image->opthdr.opt_64->FileAlignment); 125 | image->header_size = 126 | pehdr_u32(image->opthdr.opt_64->SizeOfHeaders); 127 | 128 | image->data_dir = (void *)image->opthdr.opt_64->DataDirectory; 129 | image->checksum = (uint32_t *)image->opthdr.opt_64->CheckSum; 130 | return 0; 131 | } 132 | 133 | static int align_up(int size, int align) 134 | { 135 | return (size + align - 1) & ~(align - 1); 136 | } 137 | 138 | static uint16_t csum_update_fold(uint16_t csum, uint16_t x) 139 | { 140 | uint32_t new = csum + x; 141 | new = (new >> 16) + (new & 0xffff); 142 | return new; 143 | } 144 | 145 | static uint16_t csum_bytes(uint16_t checksum, void *buf, size_t len) 146 | { 147 | unsigned int i; 148 | uint16_t *p = buf; 149 | 150 | for (i = 0; i + sizeof(*p) <= len; i += sizeof(*p)) { 151 | checksum = csum_update_fold(checksum, *p++); 152 | } 153 | 154 | /* if length is odd, add the remaining byte */ 155 | if (i < len) 156 | checksum = csum_update_fold(checksum, *((uint8_t *)p)); 157 | 158 | return checksum; 159 | } 160 | 161 | static void image_pecoff_update_checksum(struct image *image) 162 | { 163 | bool is_signed = image->sigsize && image->sigbuf; 164 | uint32_t checksum; 165 | 166 | /* We carefully only include the signature data in the checksum (and 167 | * in the file length) if we're outputting the signature. Otherwise, 168 | * in case of signature removal, the signature data is in the buffer 169 | * we read in (as indicated by image->size), but we do *not* want to 170 | * checksum it. 171 | * 172 | * We also skip the 32-bits of checksum data in the PE/COFF header. 173 | */ 174 | checksum = csum_bytes(0, image->buf, 175 | (void *)image->checksum - (void *)image->buf); 176 | checksum = csum_bytes(checksum, 177 | image->checksum + 1, 178 | (void *)(image->buf + image->data_size) - 179 | (void *)(image->checksum + 1)); 180 | 181 | if (is_signed) { 182 | checksum = csum_bytes(checksum, image->sigbuf, image->sigsize); 183 | } 184 | 185 | checksum += image->data_size; 186 | 187 | if (is_signed) 188 | checksum += image->sigsize; 189 | 190 | *(image->checksum) = cpu_to_le32(checksum); 191 | } 192 | 193 | static int image_pecoff_parse(struct image *image) 194 | { 195 | struct cert_table_header *cert_table; 196 | char nt_sig[] = {'P', 'E', 0, 0}; 197 | size_t size = image->size; 198 | int rc, cert_table_offset; 199 | void *buf = image->buf; 200 | uint16_t magic; 201 | uint32_t addr; 202 | 203 | /* sanity checks */ 204 | if (size < sizeof(*image->doshdr)) { 205 | fprintf(stderr, "file is too small for DOS header\n"); 206 | return -1; 207 | } 208 | 209 | image->doshdr = buf; 210 | 211 | if (image->doshdr->e_magic[0] != 0x4d 212 | || image->doshdr->e_magic[1] != 0x5a) { 213 | fprintf(stderr, "Invalid DOS header magic\n"); 214 | return -1; 215 | } 216 | 217 | addr = pehdr_u32(image->doshdr->e_lfanew); 218 | if (addr >= image->size) { 219 | fprintf(stderr, "pehdr is beyond end of file [0x%08x]\n", 220 | addr); 221 | return -1; 222 | } 223 | 224 | if (addr + sizeof(*image->pehdr) > image->size) { 225 | fprintf(stderr, "File not large enough to contain pehdr\n"); 226 | return -1; 227 | } 228 | 229 | image->pehdr = buf + addr; 230 | if (memcmp(image->pehdr->nt_signature, nt_sig, sizeof(nt_sig))) { 231 | fprintf(stderr, "Invalid PE header signature\n"); 232 | return -1; 233 | } 234 | 235 | /* a.out header directly follows PE header */ 236 | image->opthdr.addr = image->pehdr + 1; 237 | magic = pehdr_u16(image->pehdr->f_magic); 238 | 239 | switch (magic) { 240 | case IMAGE_FILE_MACHINE_AMD64: 241 | case IMAGE_FILE_MACHINE_AARCH64: 242 | rc = image_pecoff_parse_64(image); 243 | break; 244 | case IMAGE_FILE_MACHINE_I386: 245 | case IMAGE_FILE_MACHINE_THUMB: 246 | rc = image_pecoff_parse_32(image); 247 | break; 248 | default: 249 | fprintf(stderr, "Invalid PE header magic\n"); 250 | return -1; 251 | } 252 | 253 | if (rc) { 254 | fprintf(stderr, "Error parsing a.out header\n"); 255 | return -1; 256 | } 257 | 258 | /* the optional header has a variable size, as the data directory 259 | * has a variable number of entries. Ensure that the we have enough 260 | * space to include the security directory entry */ 261 | image->opthdr_size = pehdr_u16(image->pehdr->f_opthdr); 262 | cert_table_offset = sizeof(*image->data_dir) * 263 | (DATA_DIR_CERT_TABLE + 1); 264 | 265 | if (image->opthdr_size < image->opthdr_min_size + cert_table_offset) { 266 | fprintf(stderr, "PE opt header too small (%d bytes) to contain " 267 | "a suitable data directory (need %d bytes)\n", 268 | image->opthdr_size, 269 | image->opthdr_min_size + cert_table_offset); 270 | return -1; 271 | } 272 | 273 | 274 | image->data_dir_sigtable = &image->data_dir[DATA_DIR_CERT_TABLE]; 275 | 276 | if (image->size < sizeof(*image->doshdr) + sizeof(*image->pehdr) 277 | + image->opthdr_size) { 278 | fprintf(stderr, "file is too small for a.out header\n"); 279 | return -1; 280 | } 281 | 282 | image->cert_table_size = image->data_dir_sigtable->size; 283 | if (image->cert_table_size) 284 | cert_table = buf + image->data_dir_sigtable->addr; 285 | else 286 | cert_table = NULL; 287 | 288 | image->cert_table = cert_table; 289 | 290 | /* if we have a valid cert table header, populate sigbuf as a shadow 291 | * copy of the cert tables */ 292 | if (cert_table && cert_table->revision == CERT_TABLE_REVISION && 293 | cert_table->type == CERT_TABLE_TYPE_PKCS && 294 | cert_table->size < size) { 295 | image->sigsize = image->data_dir_sigtable->size; 296 | image->sigbuf = talloc_memdup(image, cert_table, 297 | image->sigsize); 298 | } 299 | 300 | image->sections = pehdr_u16(image->pehdr->f_nscns); 301 | image->scnhdr = image->opthdr.addr + image->opthdr_size; 302 | 303 | return 0; 304 | } 305 | 306 | static int cmp_regions(const void *p1, const void *p2) 307 | { 308 | const struct region *r1 = p1, *r2 = p2; 309 | 310 | if (r1->data < r2->data) 311 | return -1; 312 | if (r1->data > r2->data) 313 | return 1; 314 | return 0; 315 | } 316 | 317 | static void set_region_from_range(struct region *region, void *start, void *end) 318 | { 319 | region->data = start; 320 | region->size = end - start; 321 | } 322 | 323 | static int image_find_regions(struct image *image) 324 | { 325 | struct region *regions, *r; 326 | void *buf = image->buf; 327 | int i, gap_warn; 328 | size_t bytes; 329 | 330 | gap_warn = 0; 331 | 332 | /* now we know where the checksum and cert table data is, we can 333 | * construct regions that need to be signed */ 334 | bytes = 0; 335 | image->n_checksum_regions = 0; 336 | image->checksum_regions = NULL; 337 | 338 | image->n_checksum_regions = 3; 339 | image->checksum_regions = talloc_zero_array(image, 340 | struct region, 341 | image->n_checksum_regions); 342 | 343 | /* first region: beginning to checksum field */ 344 | regions = image->checksum_regions; 345 | set_region_from_range(®ions[0], buf, image->checksum); 346 | regions[0].name = "begin->cksum"; 347 | bytes += regions[0].size; 348 | 349 | bytes += sizeof(*image->checksum); 350 | 351 | /* second region: end of checksum to certificate table entry */ 352 | set_region_from_range(®ions[1], 353 | image->checksum + 1, 354 | image->data_dir_sigtable 355 | ); 356 | regions[1].name = "cksum->datadir[CERT]"; 357 | bytes += regions[1].size; 358 | 359 | bytes += sizeof(struct data_dir_entry); 360 | /* third region: end of checksum to end of headers */ 361 | set_region_from_range(®ions[2], 362 | (void *)image->data_dir_sigtable 363 | + sizeof(struct data_dir_entry), 364 | buf + image->header_size); 365 | regions[2].name = "datadir[CERT]->headers"; 366 | bytes += regions[2].size; 367 | 368 | /* add COFF sections */ 369 | for (i = 0; i < image->sections; i++) { 370 | uint32_t file_offset, file_size; 371 | int n; 372 | 373 | file_offset = pehdr_u32(image->scnhdr[i].s_scnptr); 374 | file_size = pehdr_u32(image->scnhdr[i].s_size); 375 | 376 | if (!file_size) 377 | continue; 378 | 379 | n = image->n_checksum_regions++; 380 | image->checksum_regions = talloc_realloc(image, 381 | image->checksum_regions, 382 | struct region, 383 | image->n_checksum_regions); 384 | regions = image->checksum_regions; 385 | 386 | regions[n].data = buf + file_offset; 387 | regions[n].size = file_size; 388 | regions[n].name = talloc_strndup(image->checksum_regions, 389 | image->scnhdr[i].s_name, 8); 390 | bytes += regions[n].size; 391 | 392 | if (file_offset + regions[n].size > image->size) { 393 | fprintf(stderr, "warning: file-aligned section %s " 394 | "extends beyond end of file\n", 395 | regions[n].name); 396 | } 397 | 398 | if (regions[n-1].data + regions[n-1].size 399 | != regions[n].data) { 400 | fprintf(stderr, "warning: gap in section table:\n"); 401 | fprintf(stderr, " %-8s: 0x%08tx - 0x%08tx,\n", 402 | regions[n-1].name, 403 | regions[n-1].data - buf, 404 | regions[n-1].data + 405 | regions[n-1].size - buf); 406 | fprintf(stderr, " %-8s: 0x%08tx - 0x%08tx,\n", 407 | regions[n].name, 408 | regions[n].data - buf, 409 | regions[n].data + 410 | regions[n].size - buf); 411 | 412 | 413 | gap_warn = 1; 414 | } 415 | } 416 | 417 | if (gap_warn) 418 | fprintf(stderr, "gaps in the section table may result in " 419 | "different checksums\n"); 420 | 421 | qsort(image->checksum_regions, image->n_checksum_regions, 422 | sizeof(struct region), cmp_regions); 423 | 424 | if (bytes + image->cert_table_size < image->size) { 425 | int n = image->n_checksum_regions++; 426 | struct region *r; 427 | 428 | image->checksum_regions = talloc_realloc(image, 429 | image->checksum_regions, 430 | struct region, 431 | image->n_checksum_regions); 432 | r = &image->checksum_regions[n]; 433 | r->name = "endjunk"; 434 | r->data = image->buf + bytes; 435 | r->size = image->size - bytes - image->cert_table_size; 436 | 437 | fprintf(stderr, "warning: data remaining[%zd vs %zd]: gaps " 438 | "between PE/COFF sections?\n", 439 | bytes + image->cert_table_size, image->size); 440 | } else if (bytes + image->cert_table_size > image->size) { 441 | fprintf(stderr, "warning: checksum areas are greater than " 442 | "image size. Invalid section table?\n"); 443 | } 444 | 445 | /* record the size of non-signature data */ 446 | r = &image->checksum_regions[image->n_checksum_regions - 1]; 447 | /* 448 | * The new Tianocore multisign does a stricter check of the signatures 449 | * in particular, the signature table must start at an aligned offset 450 | * fix this by adding bytes to the end of the text section (which must 451 | * be included in the hash) 452 | */ 453 | image->data_size = align_up((r->data - (void *)image->buf) + r->size, 8); 454 | 455 | return 0; 456 | } 457 | 458 | struct image *image_load(const char *filename) 459 | { 460 | struct image *image; 461 | int rc; 462 | 463 | image = talloc(NULL, struct image); 464 | if (!image) { 465 | perror("talloc(image)"); 466 | return NULL; 467 | } 468 | 469 | memset(image, 0, sizeof(*image)); 470 | rc = fileio_read_file(image, filename, &image->buf, &image->size); 471 | if (rc) 472 | goto err; 473 | 474 | reparse: 475 | rc = image_pecoff_parse(image); 476 | if (rc) 477 | goto err; 478 | 479 | rc = image_find_regions(image); 480 | if (rc) 481 | goto err; 482 | 483 | /* Some images may have incorrectly aligned sections, which get rounded 484 | * up to a size that is larger that the image itself (and the buffer 485 | * that we've allocated). We would have generated a warning about this, 486 | * but we can improve our chances that the verification hash will 487 | * succeed by padding the image out to the aligned size, and including 488 | * the pad in the signed data. 489 | * 490 | * In this case, do a realloc, but that may peturb the addresses that 491 | * we've calculated during the pecoff parsing, so we need to redo that 492 | * too. 493 | */ 494 | if (image->data_size > image->size) { 495 | image->buf = talloc_realloc(image, image->buf, uint8_t, 496 | image->data_size); 497 | memset(image->buf + image->size, 0, 498 | image->data_size - image->size); 499 | image->size = image->data_size; 500 | 501 | goto reparse; 502 | } 503 | 504 | return image; 505 | err: 506 | talloc_free(image); 507 | return NULL; 508 | } 509 | 510 | int image_hash_sha256(struct image *image, uint8_t digest[]) 511 | { 512 | struct region *region; 513 | SHA256_CTX ctx; 514 | int rc, i, n; 515 | 516 | rc = SHA256_Init(&ctx); 517 | if (!rc) 518 | return -1; 519 | 520 | n = 0; 521 | 522 | for (i = 0; i < image->n_checksum_regions; i++) { 523 | region = &image->checksum_regions[i]; 524 | n += region->size; 525 | #if 0 526 | printf("sum region: 0x%04lx -> 0x%04lx [0x%04x bytes]\n", 527 | region->data - image->buf, 528 | region->data - image->buf - 1 + region->size, 529 | region->size); 530 | 531 | #endif 532 | rc = SHA256_Update(&ctx, region->data, region->size); 533 | if (!rc) 534 | return -1; 535 | } 536 | 537 | rc = SHA256_Final(digest, &ctx); 538 | 539 | return !rc; 540 | } 541 | 542 | int image_add_signature(struct image *image, void *sig, int size) 543 | { 544 | struct cert_table_header *cth; 545 | int tot_size = size + sizeof(*cth); 546 | int aligned_size = align_up(tot_size, 8); 547 | void *start; 548 | 549 | if (image->sigbuf) { 550 | fprintf(stderr, "Image was already signed; adding additional signature\n"); 551 | image->sigbuf = talloc_realloc(image, image->sigbuf, uint8_t, 552 | image->sigsize + aligned_size); 553 | start = image->sigbuf + image->sigsize; 554 | image->sigsize += aligned_size; 555 | } else { 556 | fprintf(stderr, "Signing Unsigned original image\n"); 557 | start = image->sigbuf = talloc_array(image, uint8_t, aligned_size); 558 | image->sigsize = aligned_size; 559 | } 560 | cth = start; 561 | start += sizeof(*cth); 562 | memset(cth, 0 , sizeof(*cth)); 563 | cth->size = tot_size; 564 | cth->revision = CERT_TABLE_REVISION; 565 | cth->type = CERT_TABLE_TYPE_PKCS; 566 | memcpy(start, sig, size); 567 | if (aligned_size != tot_size) 568 | memset(start + size, 0, aligned_size - tot_size); 569 | 570 | image->cert_table = cth; 571 | 572 | return 0; 573 | } 574 | 575 | int image_get_signature(struct image *image, int signum, 576 | uint8_t **buf, size_t *size) 577 | { 578 | struct cert_table_header *header; 579 | void *addr = (void *)image->sigbuf; 580 | int i; 581 | 582 | if (!image->sigbuf) { 583 | fprintf(stderr, "No signature table present\n"); 584 | return -1; 585 | } 586 | 587 | header = addr; 588 | for (i = 0; i < signum; i++) { 589 | addr += align_up(header->size, 8); 590 | header = addr; 591 | } 592 | if (addr >= ((void *)image->sigbuf + 593 | image->sigsize)) 594 | return -1; 595 | 596 | *buf = (void *)(header + 1); 597 | *size = header->size - sizeof(*header); 598 | return 0; 599 | } 600 | 601 | int image_remove_signature(struct image *image, int signum) 602 | { 603 | uint8_t *buf; 604 | size_t size, aligned_size; 605 | int rc = image_get_signature(image, signum, &buf, &size); 606 | 607 | if (rc) 608 | return rc; 609 | 610 | buf -= sizeof(struct cert_table_header); 611 | size += sizeof(struct cert_table_header); 612 | aligned_size = align_up(size, 8); 613 | 614 | /* is signature at the end? */ 615 | if (buf + aligned_size >= (uint8_t *)image->sigbuf + image->sigsize) { 616 | /* only one signature? */ 617 | if (image->sigbuf == buf) { 618 | talloc_free(image->sigbuf); 619 | image->sigbuf = NULL; 620 | image->sigsize = 0; 621 | return 0; 622 | } 623 | } else { 624 | /* sig is in the middle ... just copy the rest over it */ 625 | memmove(buf, buf + aligned_size, image->sigsize - 626 | ((void *)buf - image->sigbuf) - aligned_size); 627 | } 628 | image->sigsize -= aligned_size; 629 | image->sigbuf = talloc_realloc(image, image->sigbuf, uint8_t, 630 | image->sigsize); 631 | return 0; 632 | 633 | } 634 | 635 | int image_write(struct image *image, const char *filename) 636 | { 637 | int fd, rc; 638 | bool is_signed; 639 | 640 | is_signed = image->sigbuf && image->sigsize; 641 | 642 | /* optionally update the image to contain signature data */ 643 | if (is_signed) { 644 | image->data_dir_sigtable->addr = image->data_size; 645 | image->data_dir_sigtable->size = image->sigsize; 646 | } else { 647 | image->data_dir_sigtable->addr = 0; 648 | image->data_dir_sigtable->size = 0; 649 | } 650 | 651 | image_pecoff_update_checksum(image); 652 | 653 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); 654 | if (fd < 0) { 655 | perror("open"); 656 | return -1; 657 | } 658 | 659 | rc = write_all(fd, image->buf, image->data_size); 660 | if (!rc) 661 | goto out; 662 | if (!is_signed) 663 | goto out; 664 | 665 | rc = write_all(fd, image->sigbuf, image->sigsize); 666 | if (!rc) 667 | goto out; 668 | 669 | out: 670 | close(fd); 671 | return !rc; 672 | } 673 | 674 | int image_write_detached(struct image *image, int signum, const char *filename) 675 | { 676 | uint8_t *sig; 677 | size_t len; 678 | int rc; 679 | 680 | rc = image_get_signature(image, signum, &sig, &len); 681 | 682 | if (rc) 683 | return rc; 684 | return fileio_write_file(filename, sig, len); 685 | } 686 | -------------------------------------------------------------------------------- /src/image.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #ifndef IMAGE_H 33 | #define IMAGE_H 34 | 35 | #include 36 | 37 | #include 38 | #define DO_NOT_DEFINE_LINENO 39 | 40 | #include "coff/external.h" 41 | #include "coff/pe.h" 42 | 43 | struct region { 44 | void *data; 45 | int size; 46 | char *name; 47 | }; 48 | 49 | struct image { 50 | uint8_t *buf; 51 | size_t size; 52 | 53 | /* size of the image, without signature */ 54 | size_t data_size; 55 | 56 | /* Pointers to interesting parts of the image */ 57 | uint32_t *checksum; 58 | struct external_PEI_DOS_hdr *doshdr; 59 | struct external_PEI_IMAGE_hdr *pehdr; 60 | union { 61 | PEPAOUTHDR *opt_64; 62 | PEAOUTHDR *opt_32; 63 | void *addr; 64 | } opthdr; 65 | /* size of a minimal opthdr for this machine, without data 66 | * directories */ 67 | unsigned int opthdr_min_size; 68 | /* size of the opthdr as specified by the image */ 69 | unsigned int opthdr_size; 70 | struct data_dir_entry *data_dir; 71 | struct data_dir_entry *data_dir_sigtable; 72 | struct external_scnhdr *scnhdr; 73 | int sections; 74 | 75 | void *cert_table; 76 | int cert_table_size; 77 | 78 | /* We cache a few values from the aout header, so we don't have to 79 | * keep checking whether to use the 32- or 64-bit version */ 80 | uint32_t file_alignment; 81 | uint32_t header_size; 82 | 83 | /* Regions that are included in the image hash: populated 84 | * during image parsing, then used during the hash process. 85 | */ 86 | struct region *checksum_regions; 87 | int n_checksum_regions; 88 | 89 | /* Generated signature */ 90 | void *sigbuf; 91 | size_t sigsize; 92 | 93 | }; 94 | 95 | struct data_dir_entry { 96 | uint32_t addr; 97 | uint32_t size; 98 | } __attribute__((packed)); 99 | 100 | struct cert_table_header { 101 | uint32_t size; 102 | uint16_t revision; 103 | uint16_t type; 104 | } __attribute__((packed)); 105 | 106 | struct image *image_load(const char *filename); 107 | 108 | int image_hash_sha256(struct image *image, uint8_t digest[]); 109 | int image_add_signature(struct image *, void *sig, int size); 110 | int image_get_signature(struct image *image, int signum, 111 | uint8_t **buf, size_t *size); 112 | int image_remove_signature(struct image *image, int signum); 113 | int image_write(struct image *image, const char *filename); 114 | int image_write_detached(struct image *image, int signum, const char *filename); 115 | 116 | #endif /* IMAGE_H */ 117 | 118 | -------------------------------------------------------------------------------- /src/sbattach.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #define _GNU_SOURCE 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | 55 | #include "config.h" 56 | 57 | #include "image.h" 58 | #include "fileio.h" 59 | 60 | static const char *toolname = "sbattach"; 61 | 62 | static struct option options[] = { 63 | { "attach", required_argument, NULL, 'a' }, 64 | { "detach", required_argument, NULL, 'd' }, 65 | { "remove", no_argument, NULL, 'r' }, 66 | { "help", no_argument, NULL, 'h' }, 67 | { "version", no_argument, NULL, 'V' }, 68 | { "signum", required_argument, NULL, 's' }, 69 | { NULL, 0, NULL, 0 }, 70 | }; 71 | 72 | static void usage(void) 73 | { 74 | printf("Usage: %s --attach \n" 75 | " or: %s --detach [--remove] \n" 76 | " or: %s --remove \n" 77 | "Attach or detach a signature file to/from a boot image\n" 78 | "\n" 79 | "Options:\n" 80 | "\t--attach set as the boot image's\n" 81 | "\t signature table\n" 82 | "\t--detach copy the boot image's signature table\n" 83 | "\t to \n" 84 | "\t--remove remove the boot image's signature\n" 85 | "\t table from the original file\n" 86 | "\t--signum signature to operate on (defaults to\n" 87 | "\t first)\n", 88 | toolname, toolname, toolname); 89 | } 90 | 91 | static void version(void) 92 | { 93 | printf("%s %s\n", toolname, VERSION); 94 | } 95 | 96 | static int detach_sig(struct image *image, int signum, const char *sig_filename) 97 | { 98 | return image_write_detached(image, signum, sig_filename); 99 | } 100 | 101 | static int attach_sig(struct image *image, const char *image_filename, 102 | const char *sig_filename) 103 | { 104 | const uint8_t *tmp_buf; 105 | uint8_t *sigbuf; 106 | size_t size; 107 | PKCS7 *p7; 108 | int rc; 109 | 110 | rc = fileio_read_file(image, sig_filename, &sigbuf, &size); 111 | if (rc) 112 | goto out; 113 | 114 | image_add_signature(image, sigbuf, size); 115 | 116 | rc = -1; 117 | tmp_buf = sigbuf; 118 | p7 = d2i_PKCS7(NULL, &tmp_buf, size); 119 | if (!p7) { 120 | fprintf(stderr, "Unable to parse signature data in file: %s\n", 121 | sig_filename); 122 | ERR_print_errors_fp(stderr); 123 | goto out; 124 | } 125 | rc = PKCS7_verify(p7, NULL, NULL, NULL, NULL, 126 | PKCS7_BINARY | PKCS7_NOVERIFY | PKCS7_NOSIGS); 127 | if (!rc) { 128 | fprintf(stderr, "PKCS7 verification failed for file %s\n", 129 | sig_filename); 130 | ERR_print_errors_fp(stderr); 131 | goto out; 132 | } 133 | 134 | rc = image_write(image, image_filename); 135 | if (rc) 136 | fprintf(stderr, "Error writing %s: %s\n", image_filename, 137 | strerror(errno)); 138 | 139 | out: 140 | talloc_free(sigbuf); 141 | return rc; 142 | } 143 | 144 | static int remove_sig(struct image *image, int signum, 145 | const char *image_filename) 146 | { 147 | int rc; 148 | 149 | rc = image_remove_signature(image, signum); 150 | 151 | if (rc) { 152 | fprintf(stderr, "Error, image has no signature at %d\n", 153 | signum + 1); 154 | return rc; 155 | } 156 | 157 | rc = image_write(image, image_filename); 158 | if (rc) 159 | fprintf(stderr, "Error writing %s: %s\n", image_filename, 160 | strerror(errno)); 161 | 162 | return rc; 163 | } 164 | 165 | enum action { 166 | ACTION_NONE, 167 | ACTION_ATTACH, 168 | ACTION_DETACH, 169 | }; 170 | 171 | int main(int argc, char **argv) 172 | { 173 | const char *image_filename, *sig_filename; 174 | struct image *image; 175 | enum action action; 176 | bool remove; 177 | int c, rc, signum = 0; 178 | 179 | action = ACTION_NONE; 180 | sig_filename = NULL; 181 | remove = false; 182 | 183 | for (;;) { 184 | int idx; 185 | c = getopt_long(argc, argv, "a:d:s:rhV", options, &idx); 186 | if (c == -1) 187 | break; 188 | 189 | switch (c) { 190 | case 'a': 191 | case 'd': 192 | if (action != ACTION_NONE) { 193 | fprintf(stderr, "Multiple actions specified\n"); 194 | usage(); 195 | return EXIT_FAILURE; 196 | } 197 | action = (c == 'a') ? ACTION_ATTACH : ACTION_DETACH; 198 | sig_filename = optarg; 199 | break; 200 | case 's': 201 | /* humans count from 1 not zero */ 202 | signum = atoi(optarg) - 1; 203 | break; 204 | case 'r': 205 | remove = true; 206 | break; 207 | case 'V': 208 | version(); 209 | return EXIT_SUCCESS; 210 | case 'h': 211 | usage(); 212 | return EXIT_SUCCESS; 213 | } 214 | } 215 | 216 | if (argc != optind + 1) { 217 | usage(); 218 | return EXIT_FAILURE; 219 | } 220 | image_filename = argv[optind]; 221 | 222 | /* sanity check action combinations */ 223 | if (action == ACTION_ATTACH && remove) { 224 | fprintf(stderr, "Can't use --remove with --attach\n"); 225 | return EXIT_FAILURE; 226 | } 227 | 228 | if (action == ACTION_NONE && !remove) { 229 | fprintf(stderr, "No action (attach/detach/remove) specified\n"); 230 | usage(); 231 | return EXIT_FAILURE; 232 | } 233 | 234 | ERR_load_crypto_strings(); 235 | OpenSSL_add_all_digests(); 236 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 237 | OPENSSL_config(NULL); 238 | #else 239 | OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 240 | #endif 241 | /* here we may get highly unlikely failures or we'll get a 242 | * complaint about FIPS signatures (usually becuase the FIPS 243 | * module isn't present). In either case ignore the errors 244 | * (malloc will cause other failures out lower down */ 245 | ERR_clear_error(); 246 | 247 | image = image_load(image_filename); 248 | if (!image) { 249 | fprintf(stderr, "Can't load image file %s\n", image_filename); 250 | return EXIT_FAILURE; 251 | } 252 | 253 | rc = 0; 254 | 255 | if (action == ACTION_ATTACH) 256 | rc = attach_sig(image, image_filename, sig_filename); 257 | 258 | else if (action == ACTION_DETACH) 259 | rc = detach_sig(image, signum, sig_filename); 260 | 261 | if (rc) 262 | goto out; 263 | 264 | if (remove) 265 | rc = remove_sig(image, signum, image_filename); 266 | 267 | out: 268 | talloc_free(image); 269 | return (rc == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 270 | } 271 | -------------------------------------------------------------------------------- /src/sbkeysync.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #define _GNU_SOURCE 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | #include 52 | #include 53 | 54 | #include "fileio.h" 55 | #include "efivars.h" 56 | 57 | static struct statfs statfstype; 58 | 59 | #define EFIVARS_MOUNTPOINT "/sys/firmware/efi/efivars" 60 | #define PSTORE_FSTYPE ((typeof(statfstype.f_type))0x6165676C) 61 | #define EFIVARS_FSTYPE ((typeof(statfstype.f_type))0xde5e81e4) 62 | 63 | #define EFI_IMAGE_SECURITY_DATABASE_GUID \ 64 | { 0xd719b2cb, 0x3d3a, 0x4596, \ 65 | { 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f } } 66 | 67 | static const char *toolname = "sbkeysync"; 68 | 69 | static const uint32_t sigdb_attrs = EFI_VARIABLE_NON_VOLATILE | 70 | EFI_VARIABLE_BOOTSERVICE_ACCESS | 71 | EFI_VARIABLE_RUNTIME_ACCESS | 72 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | 73 | EFI_VARIABLE_APPEND_WRITE; 74 | 75 | struct key_database_type { 76 | const char *name; 77 | EFI_GUID guid; 78 | }; 79 | 80 | struct key_database_type keydb_types[] = { 81 | { "PK", EFI_GLOBAL_VARIABLE }, 82 | { "KEK", EFI_GLOBAL_VARIABLE }, 83 | { "db", EFI_IMAGE_SECURITY_DATABASE_GUID }, 84 | { "dbx", EFI_IMAGE_SECURITY_DATABASE_GUID }, 85 | }; 86 | 87 | enum keydb_type { 88 | KEYDB_PK = 0, 89 | KEYDB_KEK = 1, 90 | KEYDB_DB = 2, 91 | KEYDB_DBX = 3, 92 | }; 93 | 94 | static const char *default_keystore_dirs[] = { 95 | "/etc/secureboot/keys", 96 | "/usr/share/secureboot/keys", 97 | }; 98 | 99 | 100 | struct key { 101 | EFI_GUID type; 102 | int id_len; 103 | uint8_t *id; 104 | 105 | char *description; 106 | 107 | struct list_node list; 108 | 109 | /* set for keys loaded from a filesystem keystore */ 110 | struct fs_keystore_entry *keystore_entry; 111 | }; 112 | 113 | typedef int (*key_parse_func)(struct key *, uint8_t *, size_t); 114 | 115 | struct cert_type { 116 | EFI_GUID guid; 117 | key_parse_func parse; 118 | }; 119 | 120 | struct key_database { 121 | const struct key_database_type *type; 122 | struct list_head keys; 123 | }; 124 | 125 | struct keyset { 126 | struct key_database pk; 127 | struct key_database kek; 128 | struct key_database db; 129 | struct key_database dbx; 130 | }; 131 | 132 | struct fs_keystore_entry { 133 | const struct key_database_type *type; 134 | const char *root; 135 | const char *name; 136 | uint8_t *data; 137 | size_t len; 138 | struct list_node keystore_list; 139 | struct list_node new_list; 140 | }; 141 | 142 | struct fs_keystore { 143 | struct list_head keys; 144 | }; 145 | 146 | struct sync_context { 147 | const char *efivars_dir; 148 | struct keyset *filesystem_keys; 149 | struct keyset *firmware_keys; 150 | struct fs_keystore *fs_keystore; 151 | const char **keystore_dirs; 152 | unsigned int n_keystore_dirs; 153 | struct list_head new_keys; 154 | bool verbose; 155 | bool dry_run; 156 | bool set_pk; 157 | }; 158 | 159 | 160 | #define GUID_STRLEN (8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1) 161 | static void guid_to_str(const EFI_GUID *guid, char *str) 162 | { 163 | snprintf(str, GUID_STRLEN, 164 | "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 165 | guid->Data1, guid->Data2, guid->Data3, 166 | guid->Data4[0], guid->Data4[1], 167 | guid->Data4[2], guid->Data4[3], 168 | guid->Data4[4], guid->Data4[5], 169 | guid->Data4[6], guid->Data4[7]); 170 | } 171 | 172 | static int sha256_key_parse(struct key *key, uint8_t *data, size_t len) 173 | { 174 | const unsigned int sha256_id_size = 256 / 8; 175 | unsigned int i; 176 | 177 | if (len != sha256_id_size) 178 | return -1; 179 | 180 | key->id = talloc_memdup(key, data, sha256_id_size); 181 | key->id_len = sha256_id_size; 182 | 183 | key->description = talloc_array(key, char, len * 2 + 1); 184 | for (i = 0; i < len; i++) 185 | snprintf(&key->description[i*2], 3, "%02x", data[i]); 186 | key->description[len*2] = '\0'; 187 | 188 | return 0; 189 | } 190 | 191 | static int x509_key_parse(struct key *key, uint8_t *data, size_t len) 192 | { 193 | const int description_len = 160; 194 | ASN1_INTEGER *serial; 195 | const uint8_t *tmp; 196 | X509 *x509; 197 | int rc; 198 | 199 | rc = -1; 200 | 201 | tmp = data; 202 | 203 | x509 = d2i_X509(NULL, &tmp, len); 204 | if (!x509) 205 | return -1; 206 | 207 | /* we use the X509 serial number as the key ID */ 208 | serial = X509_get_serialNumber(x509); 209 | if (!serial) 210 | goto out; 211 | 212 | key->id_len = ASN1_STRING_length(serial); 213 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 214 | key->id = talloc_memdup(key, ASN1_STRING_data(serial), key->id_len); 215 | #else 216 | key->id = talloc_memdup(key, ASN1_STRING_get0_data(serial), key->id_len); 217 | #endif 218 | 219 | key->description = talloc_array(key, char, description_len); 220 | X509_NAME_oneline(X509_get_subject_name(x509), 221 | key->description, description_len); 222 | 223 | rc = 0; 224 | 225 | out: 226 | X509_free(x509); 227 | return rc; 228 | } 229 | 230 | struct cert_type cert_types[] = { 231 | { EFI_CERT_SHA256_GUID, sha256_key_parse }, 232 | { EFI_CERT_X509_GUID, x509_key_parse }, 233 | }; 234 | 235 | static int guidcmp(const EFI_GUID *a, const EFI_GUID *b) 236 | { 237 | return memcmp(a, b, sizeof(EFI_GUID)); 238 | } 239 | 240 | static int key_parse(struct key *key, const EFI_GUID *type, 241 | uint8_t *data, size_t len) 242 | { 243 | char guid_str[GUID_STRLEN]; 244 | unsigned int i; 245 | 246 | for (i = 0; i < ARRAY_SIZE(cert_types); i++) { 247 | if (guidcmp(&cert_types[i].guid, type)) 248 | continue; 249 | 250 | return cert_types[i].parse(key, data, len); 251 | } 252 | 253 | guid_to_str(type, guid_str); 254 | printf("warning: unknown signature type found:\n %s\n", 255 | guid_str); 256 | return -1; 257 | 258 | } 259 | 260 | typedef int (*sigdata_fn)(EFI_SIGNATURE_DATA *, int, const EFI_GUID *, void *); 261 | 262 | /** 263 | * Iterates an buffer of EFI_SIGNATURE_LISTs (at db_data, of length len), 264 | * and calls fn on each EFI_SIGNATURE_DATA item found. 265 | * 266 | * fn is passed the EFI_SIGNATURE_DATA pointer, and the length of the 267 | * signature data (including GUID header), the type of the signature list, 268 | * and a context pointer. 269 | */ 270 | static int sigdb_iterate(void *db_data, size_t len, 271 | sigdata_fn fn, void *arg) 272 | { 273 | EFI_SIGNATURE_LIST *siglist; 274 | EFI_SIGNATURE_DATA *sigdata; 275 | unsigned int i, j; 276 | int rc = 0; 277 | 278 | if (len == 0) 279 | return 0; 280 | 281 | if (len < sizeof(*siglist)) 282 | return -1; 283 | 284 | for (i = 0, siglist = db_data + i; 285 | i + sizeof(*siglist) <= len && 286 | i + siglist->SignatureListSize > i && 287 | i + siglist->SignatureListSize <= len && !rc; 288 | i += siglist->SignatureListSize, 289 | siglist = db_data + i) { 290 | 291 | /* ensure that the header & sig sizes are sensible */ 292 | if (siglist->SignatureHeaderSize > siglist->SignatureListSize) 293 | continue; 294 | 295 | if (siglist->SignatureSize > siglist->SignatureListSize) 296 | continue; 297 | 298 | if (siglist->SignatureSize < sizeof(*sigdata)) 299 | continue; 300 | 301 | /* iterate through the (constant-sized) signature data blocks */ 302 | for (j = sizeof(*siglist) + siglist->SignatureHeaderSize; 303 | j < siglist->SignatureListSize && !rc; 304 | j += siglist->SignatureSize) 305 | { 306 | sigdata = (void *)(siglist) + j; 307 | 308 | rc = fn(sigdata, siglist->SignatureSize, 309 | &siglist->SignatureType, arg); 310 | 311 | } 312 | 313 | } 314 | 315 | return rc; 316 | } 317 | 318 | struct keydb_add_ctx { 319 | struct fs_keystore_entry *ke; 320 | struct key_database *kdb; 321 | struct keyset *keyset; 322 | }; 323 | 324 | static int keydb_add_key(EFI_SIGNATURE_DATA *sigdata, int len, 325 | const EFI_GUID *type, void *arg) 326 | { 327 | struct keydb_add_ctx *add_ctx = arg; 328 | struct key *key; 329 | int rc; 330 | 331 | key = talloc(add_ctx->keyset, struct key); 332 | 333 | rc = key_parse(key, type, sigdata->SignatureData, 334 | len - sizeof(*sigdata)); 335 | 336 | if (rc) { 337 | talloc_free(key); 338 | return 0; 339 | } 340 | key->keystore_entry = add_ctx->ke; 341 | key->type = *type; 342 | 343 | /* add a reference to the keystore entry: we don't want it to be 344 | * deallocated if the keystore is deallocated before the 345 | * struct key. */ 346 | if (key->keystore_entry) 347 | talloc_reference(key, key->keystore_entry); 348 | 349 | list_add(&add_ctx->kdb->keys, &key->list); 350 | 351 | return 0; 352 | } 353 | 354 | static int read_firmware_keydb(struct sync_context *ctx, 355 | struct key_database *kdb) 356 | { 357 | struct keydb_add_ctx add_ctx; 358 | char guid_str[GUID_STRLEN]; 359 | char *filename; 360 | uint8_t *buf; 361 | int rc = -1; 362 | size_t len; 363 | 364 | add_ctx.keyset = ctx->firmware_keys; 365 | add_ctx.kdb = kdb; 366 | add_ctx.ke = NULL; 367 | 368 | guid_to_str(&kdb->type->guid, guid_str); 369 | 370 | filename = talloc_asprintf(ctx->firmware_keys, "%s/%s-%s", 371 | ctx->efivars_dir, kdb->type->name, guid_str); 372 | 373 | buf = NULL; 374 | rc = fileio_read_file_noerror(ctx->firmware_keys, filename, &buf, &len); 375 | if (rc) 376 | goto out; 377 | 378 | /* efivars files start with a 32-bit attribute block */ 379 | if (len < sizeof(uint32_t)) 380 | goto out; 381 | 382 | buf += sizeof(uint32_t); 383 | len -= sizeof(uint32_t); 384 | 385 | rc = 0; 386 | sigdb_iterate(buf, len, keydb_add_key, &add_ctx); 387 | 388 | out: 389 | if (rc) 390 | talloc_free(buf); 391 | talloc_free(filename); 392 | 393 | return rc; 394 | } 395 | 396 | static void __attribute__((format(printf, 2, 3))) print_keystore_key_error( 397 | struct fs_keystore_entry *ke, const char *fmt, ...) 398 | { 399 | char *errstr; 400 | va_list ap; 401 | 402 | va_start(ap, fmt); 403 | errstr = talloc_vasprintf(ke, fmt, ap); 404 | 405 | fprintf(stderr, "Invalid key %s/%s\n - %s\n", ke->root, ke->name, 406 | errstr); 407 | 408 | talloc_free(errstr); 409 | va_end(ap); 410 | } 411 | 412 | static int read_filesystem_keydb(struct sync_context *ctx, 413 | struct key_database *kdb) 414 | { 415 | EFI_GUID cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; 416 | EFI_VARIABLE_AUTHENTICATION_2 *auth; 417 | struct keydb_add_ctx add_ctx; 418 | struct fs_keystore_entry *ke; 419 | int rc; 420 | 421 | add_ctx.keyset = ctx->filesystem_keys; 422 | add_ctx.kdb = kdb; 423 | 424 | list_for_each(&ctx->fs_keystore->keys, ke, keystore_list) { 425 | unsigned int len; 426 | void *buf; 427 | 428 | if (ke->len == 0) 429 | continue; 430 | 431 | if (ke->type != kdb->type) 432 | continue; 433 | 434 | /* parse the three data structures: 435 | * EFI_VARIABLE_AUTHENTICATION_2 token 436 | * EFI_SIGNATURE_LIST 437 | * EFI_SIGNATURE_DATA 438 | * ensuring that we have enough data for each 439 | */ 440 | 441 | buf = ke->data; 442 | len = ke->len; 443 | 444 | if (len < sizeof(*auth)) { 445 | print_keystore_key_error(ke, "does not contain an " 446 | "EFI_VARIABLE_AUTHENTICATION_2 descriptor"); 447 | continue; 448 | } 449 | 450 | auth = buf; 451 | 452 | if (guidcmp(&auth->AuthInfo.CertType, &cert_type_pkcs7)) { 453 | print_keystore_key_error(ke, "unknown cert type"); 454 | continue; 455 | } 456 | 457 | if (auth->AuthInfo.Hdr.dwLength > len) { 458 | print_keystore_key_error(ke, 459 | "invalid WIN_CERTIFICATE length"); 460 | continue; 461 | } 462 | 463 | /* the dwLength field includes the size of the WIN_CERTIFICATE, 464 | * but not the other data in the EFI_VARIABLE_AUTHENTICATION_2 465 | * descriptor */ 466 | buf += sizeof(*auth) - sizeof(auth->AuthInfo) + 467 | auth->AuthInfo.Hdr.dwLength; 468 | len -= sizeof(*auth) - sizeof(auth->AuthInfo) + 469 | auth->AuthInfo.Hdr.dwLength; 470 | 471 | add_ctx.ke = ke; 472 | rc = sigdb_iterate(buf, len, keydb_add_key, &add_ctx); 473 | if (rc) { 474 | print_keystore_key_error(ke, "error parsing " 475 | "EFI_SIGNATURE_LIST"); 476 | continue; 477 | } 478 | 479 | } 480 | 481 | return 0; 482 | } 483 | 484 | static int read_keysets(struct sync_context *ctx) 485 | { 486 | read_firmware_keydb(ctx, &ctx->firmware_keys->pk); 487 | read_firmware_keydb(ctx, &ctx->firmware_keys->kek); 488 | read_firmware_keydb(ctx, &ctx->firmware_keys->db); 489 | read_firmware_keydb(ctx, &ctx->firmware_keys->dbx); 490 | 491 | read_filesystem_keydb(ctx, &ctx->filesystem_keys->pk); 492 | read_filesystem_keydb(ctx, &ctx->filesystem_keys->kek); 493 | read_filesystem_keydb(ctx, &ctx->filesystem_keys->db); 494 | read_filesystem_keydb(ctx, &ctx->filesystem_keys->dbx); 495 | 496 | return 0; 497 | } 498 | 499 | static int check_pk(struct sync_context *ctx) 500 | { 501 | struct key *key; 502 | int i = 0; 503 | 504 | list_for_each(&ctx->filesystem_keys->pk.keys, key, list) 505 | i++; 506 | 507 | return (i <= 1) ? 0 : 1; 508 | } 509 | 510 | static void print_keyset(struct keyset *keyset, const char *name) 511 | { 512 | struct key_database *kdbs[] = 513 | { &keyset->pk, &keyset->kek, &keyset->db, &keyset->dbx }; 514 | struct key *key; 515 | unsigned int i; 516 | 517 | printf("%s keys:\n", name); 518 | 519 | for (i = 0; i < ARRAY_SIZE(kdbs); i++) { 520 | printf(" %s:\n", kdbs[i]->type->name); 521 | 522 | list_for_each(&kdbs[i]->keys, key, list) { 523 | printf(" %s\n", key->description); 524 | if (key->keystore_entry) 525 | printf(" from %s/%s\n", 526 | key->keystore_entry->root, 527 | key->keystore_entry->name); 528 | } 529 | } 530 | } 531 | 532 | static int check_efivars_mount(const char *mountpoint) 533 | { 534 | struct statfs statbuf; 535 | int rc; 536 | 537 | rc = statfs(mountpoint, &statbuf); 538 | if (rc) 539 | return -1; 540 | 541 | if (statbuf.f_type != EFIVARS_FSTYPE && statbuf.f_type != PSTORE_FSTYPE) 542 | return -1; 543 | 544 | return 0; 545 | } 546 | 547 | static int keystore_entry_read(struct fs_keystore_entry *ke) 548 | { 549 | const char *path; 550 | int rc; 551 | 552 | path = talloc_asprintf(ke, "%s/%s", ke->root, ke->name); 553 | 554 | rc = fileio_read_file(ke, path, &ke->data, &ke->len); 555 | 556 | talloc_free(path); 557 | 558 | return rc; 559 | } 560 | 561 | static bool keystore_contains_file(struct fs_keystore *keystore, 562 | const char *filename) 563 | { 564 | struct fs_keystore_entry *ke; 565 | 566 | list_for_each(&keystore->keys, ke, keystore_list) { 567 | if (!strcmp(ke->name, filename)) 568 | return true; 569 | } 570 | 571 | return false; 572 | } 573 | 574 | static int update_keystore(struct fs_keystore *keystore, const char *root) 575 | { 576 | struct fs_keystore_entry *ke; 577 | unsigned int i; 578 | 579 | for (i = 0; i < ARRAY_SIZE(keydb_types); i++) { 580 | const char *filename, *dirname; 581 | struct dirent *dirent; 582 | DIR *dir; 583 | 584 | dirname = talloc_asprintf(keystore, "%s/%s", root, 585 | keydb_types[i].name); 586 | 587 | dir = opendir(dirname); 588 | if (!dir) 589 | continue; 590 | 591 | for (dirent = readdir(dir); dirent; dirent = readdir(dir)) { 592 | 593 | if (dirent->d_name[0] == '.') 594 | continue; 595 | 596 | filename = talloc_asprintf(dirname, "%s/%s", 597 | keydb_types[i].name, 598 | dirent->d_name); 599 | 600 | if (keystore_contains_file(keystore, filename)) 601 | continue; 602 | 603 | ke = talloc(keystore, struct fs_keystore_entry); 604 | ke->name = filename; 605 | ke->root = root; 606 | ke->type = &keydb_types[i]; 607 | talloc_steal(ke, ke->name); 608 | 609 | if (keystore_entry_read(ke)) 610 | talloc_free(ke); 611 | else 612 | list_add(&keystore->keys, &ke->keystore_list); 613 | } 614 | 615 | closedir(dir); 616 | talloc_free(dirname); 617 | } 618 | 619 | return 0; 620 | } 621 | 622 | static int read_keystore(struct sync_context *ctx) 623 | { 624 | struct fs_keystore *keystore; 625 | unsigned int i; 626 | 627 | keystore = talloc(ctx, struct fs_keystore); 628 | list_head_init(&keystore->keys); 629 | 630 | for (i = 0; i < ctx->n_keystore_dirs; i++) { 631 | update_keystore(keystore, ctx->keystore_dirs[i]); 632 | } 633 | 634 | ctx->fs_keystore = keystore; 635 | 636 | return 0; 637 | } 638 | 639 | static void print_keystore(struct fs_keystore *keystore) 640 | { 641 | struct fs_keystore_entry *ke; 642 | 643 | printf("Filesystem keystore:\n"); 644 | 645 | list_for_each(&keystore->keys, ke, keystore_list) 646 | printf(" %s/%s [%zd bytes]\n", ke->root, ke->name, ke->len); 647 | } 648 | 649 | static int key_cmp(struct key *a, struct key *b) 650 | { 651 | if (a->id_len != b->id_len) 652 | return a->id_len - b->id_len; 653 | 654 | return memcmp(a->id, b->id, a->id_len); 655 | } 656 | 657 | /** 658 | * Finds the set-difference of the filesystem and firmware keys, and 659 | * populates ctx->new_keys with the keystore_entries that should be 660 | * inserted into firmware 661 | */ 662 | static int find_new_keys(struct sync_context *ctx) 663 | { 664 | struct { 665 | struct key_database *fs_kdb, *fw_kdb; 666 | } kdbs[] = { 667 | { &ctx->filesystem_keys->pk, &ctx->firmware_keys->pk }, 668 | { &ctx->filesystem_keys->kek, &ctx->firmware_keys->kek }, 669 | { &ctx->filesystem_keys->db, &ctx->firmware_keys->db }, 670 | { &ctx->filesystem_keys->dbx, &ctx->firmware_keys->dbx }, 671 | }; 672 | unsigned int i; 673 | int n = 0; 674 | 675 | for (i = 0; i < ARRAY_SIZE(kdbs); i++ ) { 676 | struct fs_keystore_entry *ke; 677 | struct key *fs_key, *fw_key; 678 | bool found; 679 | 680 | list_for_each(&kdbs[i].fs_kdb->keys, fs_key, list) { 681 | found = false; 682 | list_for_each(&kdbs[i].fw_kdb->keys, fw_key, list) { 683 | if (!key_cmp(fs_key, fw_key)) { 684 | found = true; 685 | break; 686 | } 687 | } 688 | if (found) 689 | continue; 690 | 691 | /* add the keystore entry if it's not already present */ 692 | found = false; 693 | list_for_each(&ctx->new_keys, ke, new_list) { 694 | if (fs_key->keystore_entry == ke) { 695 | found = true; 696 | break; 697 | } 698 | } 699 | 700 | if (found) 701 | continue; 702 | 703 | list_add(&ctx->new_keys, 704 | &fs_key->keystore_entry->new_list); 705 | n++; 706 | } 707 | } 708 | 709 | return n; 710 | } 711 | 712 | static void print_new_keys(struct sync_context *ctx) 713 | { 714 | struct fs_keystore_entry *ke; 715 | 716 | printf("New keys in filesystem:\n"); 717 | 718 | list_for_each(&ctx->new_keys, ke, new_list) 719 | printf(" %s/%s\n", ke->root, ke->name); 720 | } 721 | 722 | static int insert_key(struct sync_context *ctx, struct fs_keystore_entry *ke) 723 | { 724 | char guid_str[GUID_STRLEN]; 725 | char *efivars_filename; 726 | unsigned int buf_len; 727 | uint8_t *buf; 728 | int fd, rc; 729 | 730 | fd = -1; 731 | rc = -1; 732 | 733 | if (ctx->verbose) 734 | printf("Inserting key update %s/%s into %s\n", 735 | ke->root, ke->name, ke->type->name); 736 | 737 | /* we create a contiguous buffer of attributes & key data, so that 738 | * we write to the efivars file in a single syscall */ 739 | buf_len = sizeof(sigdb_attrs) + ke->len; 740 | buf = talloc_array(ke, uint8_t, buf_len); 741 | memcpy(buf, &sigdb_attrs, sizeof(sigdb_attrs)); 742 | memcpy(buf + sizeof(sigdb_attrs), ke->data, ke->len); 743 | 744 | guid_to_str(&ke->type->guid, guid_str); 745 | 746 | efivars_filename = talloc_asprintf(ke, "%s/%s-%s", ctx->efivars_dir, 747 | ke->type->name, guid_str); 748 | 749 | fd = open(efivars_filename, O_WRONLY | O_CREAT, 0600); 750 | if (fd < 0) { 751 | fprintf(stderr, "Can't create key file %s: %s\n", 752 | efivars_filename, strerror(errno)); 753 | goto out; 754 | } 755 | 756 | rc = write(fd, buf, buf_len); 757 | if (rc <= 0) { 758 | fprintf(stderr, "Error writing key update: %s\n", 759 | strerror(errno)); 760 | goto out; 761 | } 762 | 763 | if (rc != (int)buf_len) { 764 | fprintf(stderr, "Partial write during key update: " 765 | "wrote %d bytes, expecting %d\n", 766 | rc, buf_len); 767 | goto out; 768 | } 769 | 770 | rc = 0; 771 | 772 | out: 773 | if (fd >= 0) 774 | close(fd); 775 | talloc_free(efivars_filename); 776 | talloc_free(buf); 777 | if (rc) 778 | fprintf(stderr, "Error syncing keystore file %s/%s\n", 779 | ke->root, ke->name); 780 | return rc; 781 | } 782 | 783 | static int insert_new_keys(struct sync_context *ctx) 784 | { 785 | struct fs_keystore_entry *ke, *ke_pk; 786 | int pks, rc; 787 | 788 | rc = 0; 789 | pks = 0; 790 | ke_pk = NULL; 791 | 792 | list_for_each(&ctx->new_keys, ke, new_list) { 793 | 794 | /* we handle PK last */ 795 | if (ke->type == &keydb_types[KEYDB_PK]) { 796 | ke_pk = ke; 797 | pks++; 798 | continue; 799 | } 800 | 801 | if (insert_key(ctx, ke)) 802 | rc = -1; 803 | } 804 | 805 | if (rc) 806 | return rc; 807 | 808 | if (pks == 0 || !ctx->set_pk) 809 | return 0; 810 | 811 | if (pks > 1) { 812 | fprintf(stderr, "Skipping PK update due to mutiple PKs\n"); 813 | return -1; 814 | } 815 | 816 | rc = insert_key(ctx, ke_pk); 817 | 818 | return rc; 819 | } 820 | 821 | static struct keyset *init_keyset(struct sync_context *ctx) 822 | { 823 | struct keyset *keyset; 824 | 825 | keyset = talloc(ctx, struct keyset); 826 | 827 | list_head_init(&keyset->pk.keys); 828 | keyset->pk.type = &keydb_types[KEYDB_PK]; 829 | 830 | list_head_init(&keyset->kek.keys); 831 | keyset->kek.type = &keydb_types[KEYDB_KEK]; 832 | 833 | list_head_init(&keyset->db.keys); 834 | keyset->db.type = &keydb_types[KEYDB_DB]; 835 | 836 | list_head_init(&keyset->dbx.keys); 837 | keyset->dbx.type = &keydb_types[KEYDB_DBX]; 838 | 839 | return keyset; 840 | } 841 | 842 | static struct option options[] = { 843 | { "help", no_argument, NULL, 'h' }, 844 | { "version", no_argument, NULL, 'V' }, 845 | { "efivars-path", required_argument, NULL, 'e' }, 846 | { "verbose", no_argument, NULL, 'v' }, 847 | { "dry-run", no_argument, NULL, 'n' }, 848 | { "pk", no_argument, NULL, 'p' }, 849 | { "no-default-keystores", no_argument, NULL, 'd' }, 850 | { "keystore", required_argument, NULL, 'k' }, 851 | { NULL, 0, NULL, 0 }, 852 | }; 853 | 854 | static void usage(void) 855 | { 856 | printf("Usage: %s [options]\n" 857 | "Update EFI key databases from the filesystem\n" 858 | "\n" 859 | "Options:\n" 860 | "\t--efivars-path Path to efivars mountpoint\n" 861 | "\t (or regular directory for testing)\n" 862 | "\t--verbose Print verbose progress information\n" 863 | "\t--dry-run Don't update firmware key databases\n" 864 | "\t--pk Set PK\n" 865 | "\t--keystore Read keys from /{db,dbx,KEK}/*\n" 866 | "\t (can be specified multiple times,\n" 867 | "\t first dir takes precedence)\n" 868 | "\t--no-default-keystores\n" 869 | "\t Don't read keys from the default\n" 870 | "\t keystore dirs\n", 871 | toolname); 872 | } 873 | 874 | static void version(void) 875 | { 876 | printf("%s %s\n", toolname, VERSION); 877 | } 878 | 879 | static void add_keystore_dir(struct sync_context *ctx, const char *dir) 880 | { 881 | ctx->keystore_dirs = talloc_realloc(ctx, ctx->keystore_dirs, 882 | const char *, ++ctx->n_keystore_dirs); 883 | 884 | ctx->keystore_dirs[ctx->n_keystore_dirs - 1] = 885 | talloc_strdup(ctx->keystore_dirs, dir); 886 | } 887 | 888 | int main(int argc, char **argv) 889 | { 890 | bool use_default_keystore_dirs; 891 | struct sync_context *ctx; 892 | 893 | use_default_keystore_dirs = true; 894 | ctx = talloc_zero(NULL, struct sync_context); 895 | list_head_init(&ctx->new_keys); 896 | 897 | for (;;) { 898 | int idx, c; 899 | c = getopt_long(argc, argv, "e:dpkvhV", options, &idx); 900 | if (c == -1) 901 | break; 902 | 903 | switch (c) { 904 | case 'e': 905 | ctx->efivars_dir = optarg; 906 | break; 907 | case 'd': 908 | use_default_keystore_dirs = false; 909 | break; 910 | case 'k': 911 | add_keystore_dir(ctx, optarg); 912 | break; 913 | case 'p': 914 | ctx->set_pk = true; 915 | break; 916 | case 'v': 917 | ctx->verbose = true; 918 | break; 919 | case 'n': 920 | ctx->dry_run = true; 921 | break; 922 | case 'V': 923 | version(); 924 | return EXIT_SUCCESS; 925 | case 'h': 926 | usage(); 927 | return EXIT_SUCCESS; 928 | } 929 | } 930 | 931 | if (argc != optind) { 932 | usage(); 933 | return EXIT_FAILURE; 934 | } 935 | 936 | ERR_load_crypto_strings(); 937 | OpenSSL_add_all_digests(); 938 | OpenSSL_add_all_ciphers(); 939 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 940 | OPENSSL_config(NULL); 941 | #else 942 | OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 943 | #endif 944 | /* here we may get highly unlikely failures or we'll get a 945 | * complaint about FIPS signatures (usually becuase the FIPS 946 | * module isn't present). In either case ignore the errors 947 | * (malloc will cause other failures out lower down */ 948 | ERR_clear_error(); 949 | 950 | ctx->filesystem_keys = init_keyset(ctx); 951 | ctx->firmware_keys = init_keyset(ctx); 952 | 953 | if (!ctx->efivars_dir) { 954 | ctx->efivars_dir = EFIVARS_MOUNTPOINT; 955 | if (check_efivars_mount(ctx->efivars_dir)) { 956 | fprintf(stderr, "Can't access efivars filesystem " 957 | "at %s, aborting\n", ctx->efivars_dir); 958 | return EXIT_FAILURE; 959 | } 960 | } 961 | 962 | if (use_default_keystore_dirs) { 963 | unsigned int i; 964 | for (i = 0; i < ARRAY_SIZE(default_keystore_dirs); i++) 965 | add_keystore_dir(ctx, default_keystore_dirs[i]); 966 | } 967 | 968 | 969 | read_keystore(ctx); 970 | 971 | if (ctx->verbose) 972 | print_keystore(ctx->fs_keystore); 973 | 974 | read_keysets(ctx); 975 | if (ctx->verbose) { 976 | print_keyset(ctx->firmware_keys, "firmware"); 977 | print_keyset(ctx->filesystem_keys, "filesystem"); 978 | } 979 | 980 | if (check_pk(ctx)) 981 | fprintf(stderr, "WARNING: multiple PKs found in filesystem\n"); 982 | 983 | find_new_keys(ctx); 984 | 985 | if (ctx->verbose) 986 | print_new_keys(ctx); 987 | 988 | if (!ctx->dry_run) 989 | insert_new_keys(ctx); 990 | 991 | talloc_free(ctx); 992 | 993 | return EXIT_SUCCESS; 994 | } 995 | -------------------------------------------------------------------------------- /src/sbsiglist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #define _GNU_SOURCE 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #include 54 | #include 55 | #include 56 | 57 | #include "efivars.h" 58 | #include "fileio.h" 59 | 60 | static const char *toolname = "sbsiglist"; 61 | 62 | static struct option options[] = { 63 | { "output", required_argument, NULL, 'o' }, 64 | { "type", required_argument, NULL, 't' }, 65 | { "owner", required_argument, NULL, 'w' }, 66 | { "verbose", no_argument, NULL, 'v' }, 67 | { "help", no_argument, NULL, 'h' }, 68 | { "version", no_argument, NULL, 'V' }, 69 | { NULL, 0, NULL, 0 }, 70 | }; 71 | 72 | struct cert_type { 73 | const char *name; 74 | const EFI_GUID guid; 75 | unsigned int sigsize; 76 | }; 77 | 78 | struct cert_type cert_types[] = { 79 | { "x509", EFI_CERT_X509_GUID, 0 }, 80 | { "sha256", EFI_CERT_SHA256_GUID, 32 }, 81 | }; 82 | 83 | struct siglist_context { 84 | int verbose; 85 | 86 | const char *infilename; 87 | const char *outfilename; 88 | const struct cert_type *type; 89 | EFI_GUID owner; 90 | 91 | uint8_t *data; 92 | size_t data_len; 93 | 94 | EFI_SIGNATURE_LIST *siglist; 95 | }; 96 | 97 | 98 | void usage(void) 99 | { 100 | unsigned int i; 101 | 102 | printf("Usage: %s [options] --owner --type \n" 103 | "Create an EFI_SIGNATURE_LIST from a signature file\n" 104 | "Options:\n" 105 | "\t--owner Signature owner GUID\n" 106 | "\t--type Signature type. One of:\n", 107 | toolname); 108 | 109 | for (i = 0; i < ARRAY_SIZE(cert_types); i++) 110 | printf("\t %s\n", cert_types[i].name); 111 | 112 | printf("\t--output write signed data to \n" 113 | "\t (default .siglist)\n"); 114 | } 115 | 116 | static void version(void) 117 | { 118 | printf("%s %s\n", toolname, VERSION); 119 | } 120 | 121 | static int siglist_create(struct siglist_context *ctx) 122 | { 123 | EFI_SIGNATURE_LIST *siglist; 124 | EFI_SIGNATURE_DATA *sigdata; 125 | uint32_t size; 126 | 127 | if (ctx->type->sigsize && ctx->data_len != ctx->type->sigsize) { 128 | fprintf(stderr, "Error: signature lists of type '%s' expect " 129 | "%d bytes of data, " 130 | "%zd bytes provided.\n", 131 | ctx->type->name, 132 | ctx->type->sigsize, 133 | ctx->data_len); 134 | return -1; 135 | } 136 | 137 | size = sizeof(*siglist) + sizeof(*sigdata) + ctx->data_len; 138 | 139 | siglist = talloc_size(ctx, size); 140 | sigdata = (void *)(siglist + 1); 141 | 142 | siglist->SignatureType = ctx->type->guid; 143 | siglist->SignatureListSize = size; 144 | siglist->SignatureHeaderSize = 0; 145 | siglist->SignatureSize = ctx->data_len + sizeof(*sigdata); 146 | 147 | sigdata->SignatureOwner = ctx->owner; 148 | 149 | memcpy(sigdata->SignatureData, ctx->data, ctx->data_len); 150 | 151 | ctx->siglist = siglist; 152 | 153 | return 0; 154 | } 155 | 156 | static int parse_guid(const char *str, EFI_GUID *guid) 157 | { 158 | uuid_t uuid; 159 | 160 | if (uuid_parse(str, uuid)) 161 | return -1; 162 | 163 | /* convert to an EFI_GUID */ 164 | guid->Data1 = uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3]; 165 | guid->Data2 = uuid[4] << 8 | uuid[5]; 166 | guid->Data3 = uuid[6] << 8 | uuid[7]; 167 | memcpy(guid->Data4, &uuid[8], sizeof(guid->Data4)); 168 | 169 | return 0; 170 | } 171 | 172 | static struct cert_type *parse_type(const char *str) 173 | { 174 | unsigned int i; 175 | 176 | for (i = 0; i < ARRAY_SIZE(cert_types); i++) 177 | if (!strcasecmp(cert_types[i].name, str)) 178 | return &cert_types[i]; 179 | 180 | return NULL; 181 | } 182 | 183 | static void set_default_outfilename(struct siglist_context *ctx) 184 | { 185 | const char *extension = "siglist"; 186 | 187 | ctx->outfilename = talloc_asprintf(ctx, "%s.%s", 188 | ctx->infilename, extension); 189 | } 190 | int main(int argc, char **argv) 191 | { 192 | const char *type_str, *owner_guid_str; 193 | struct siglist_context *ctx; 194 | int c; 195 | 196 | ctx = talloc_zero(NULL, struct siglist_context); 197 | 198 | owner_guid_str = NULL; 199 | type_str = NULL; 200 | 201 | for (;;) { 202 | int idx; 203 | c = getopt_long(argc, argv, "o:t:w:ivVh", options, &idx); 204 | if (c == -1) 205 | break; 206 | 207 | switch (c) { 208 | case 'o': 209 | ctx->outfilename = optarg; 210 | break; 211 | case 't': 212 | type_str = optarg; 213 | break; 214 | case 'w': 215 | owner_guid_str = optarg; 216 | break; 217 | case 'v': 218 | ctx->verbose = 1; 219 | break; 220 | case 'V': 221 | version(); 222 | return EXIT_SUCCESS; 223 | case 'h': 224 | usage(); 225 | return EXIT_SUCCESS; 226 | } 227 | } 228 | 229 | if (argc != optind + 1) { 230 | usage(); 231 | return EXIT_FAILURE; 232 | } 233 | 234 | ctx->infilename = argv[optind]; 235 | 236 | if (!type_str) { 237 | fprintf(stderr, "No type specified\n"); 238 | usage(); 239 | return EXIT_FAILURE; 240 | } 241 | 242 | if (!type_str) { 243 | fprintf(stderr, "No owner specified\n"); 244 | usage(); 245 | return EXIT_FAILURE; 246 | } 247 | 248 | ctx->type = parse_type(type_str); 249 | if (!ctx->type) { 250 | fprintf(stderr, "Invalid type '%s'\n", type_str); 251 | return EXIT_FAILURE; 252 | } 253 | 254 | if (parse_guid(owner_guid_str, &ctx->owner)) { 255 | fprintf(stderr, "Invalid owner GUID '%s'\n", owner_guid_str); 256 | return EXIT_FAILURE; 257 | } 258 | 259 | if (!ctx->outfilename) 260 | set_default_outfilename(ctx); 261 | 262 | if (fileio_read_file(ctx, ctx->infilename, 263 | &ctx->data, &ctx->data_len)) { 264 | fprintf(stderr, "Can't read input file %s\n", ctx->infilename); 265 | return EXIT_FAILURE; 266 | } 267 | 268 | if (siglist_create(ctx)) 269 | return EXIT_FAILURE; 270 | 271 | if (fileio_write_file(ctx->outfilename, 272 | (void *)ctx->siglist, 273 | ctx->siglist->SignatureListSize)) { 274 | fprintf(stderr, "Can't write output file %s\n", 275 | ctx->outfilename); 276 | return EXIT_FAILURE; 277 | } 278 | 279 | return EXIT_SUCCESS; 280 | } 281 | -------------------------------------------------------------------------------- /src/sbsign.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #define _GNU_SOURCE 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | 57 | #include "idc.h" 58 | #include "image.h" 59 | #include "fileio.h" 60 | 61 | static const char *toolname = "sbsign"; 62 | 63 | struct sign_context { 64 | struct image *image; 65 | const char *infilename; 66 | const char *outfilename; 67 | int verbose; 68 | int detached; 69 | }; 70 | 71 | static struct option options[] = { 72 | { "output", required_argument, NULL, 'o' }, 73 | { "cert", required_argument, NULL, 'c' }, 74 | { "key", required_argument, NULL, 'k' }, 75 | { "detached", no_argument, NULL, 'd' }, 76 | { "verbose", no_argument, NULL, 'v' }, 77 | { "help", no_argument, NULL, 'h' }, 78 | { "hash-only", no_argument, NULL, 'H' }, 79 | { "version", no_argument, NULL, 'V' }, 80 | { "engine", required_argument, NULL, 'e'}, 81 | { "addcert", required_argument, NULL, 'a'}, 82 | { NULL, 0, NULL, 0 }, 83 | }; 84 | 85 | static void usage(void) 86 | { 87 | printf("Usage: %s [options] --key --cert " 88 | "\n" 89 | "Sign an EFI boot image for use with secure boot.\n\n" 90 | "Options:\n" 91 | "\t--engine use the specified engine to load the key\n" 92 | "\t--key signing key (PEM-encoded RSA " 93 | "private key)\n" 94 | "\t--cert certificate (x509 certificate)\n" 95 | "\t--addcert additional intermediate certificates in a file\n" 96 | "\t--detached write a detached signature, instead of\n" 97 | "\t a signed binary\n" 98 | "\t--output write signed data to \n" 99 | "\t (default .signed,\n" 100 | "\t or .pk7 for detached\n" 101 | "\t signatures)\n" 102 | "\t--hash-only Print the PE hash\n", 103 | toolname); 104 | } 105 | 106 | static void version(void) 107 | { 108 | printf("%s %s\n", toolname, VERSION); 109 | } 110 | 111 | static void set_default_outfilename(struct sign_context *ctx) 112 | { 113 | const char *extension; 114 | 115 | extension = ctx->detached ? "pk7" : "signed"; 116 | 117 | ctx->outfilename = talloc_asprintf(ctx, "%s.%s", 118 | ctx->infilename, extension); 119 | } 120 | 121 | static int add_intermediate_certs(PKCS7 *p7, const char *filename) 122 | { 123 | STACK_OF(X509_INFO) *certs; 124 | X509_INFO *cert; 125 | BIO *bio = NULL; 126 | int i; 127 | 128 | bio = BIO_new(BIO_s_file()); 129 | if (!bio || BIO_read_filename(bio, filename) <=0) { 130 | fprintf(stderr, 131 | "error in reading intermediate certificates file\n"); 132 | ERR_print_errors_fp(stderr); 133 | return -1; 134 | } 135 | 136 | certs = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); 137 | if (!certs) { 138 | fprintf(stderr, 139 | "error in parsing intermediate certificates file\n"); 140 | ERR_print_errors_fp(stderr); 141 | return -1; 142 | } 143 | 144 | for (i = 0; i < sk_X509_INFO_num(certs); i++) { 145 | cert = sk_X509_INFO_value(certs, i); 146 | PKCS7_add_certificate(p7, cert->x509); 147 | } 148 | 149 | sk_X509_INFO_pop_free(certs, X509_INFO_free); 150 | BIO_free_all(bio); 151 | 152 | return 0; 153 | } 154 | 155 | int main(int argc, char **argv) 156 | { 157 | const char *keyfilename, *certfilename, *addcertfilename, *engine; 158 | struct sign_context *ctx; 159 | uint8_t *buf, *tmp; 160 | int rc, c, sigsize, hash_only = 0;; 161 | EVP_PKEY *pkey; 162 | 163 | ctx = talloc_zero(NULL, struct sign_context); 164 | 165 | keyfilename = NULL; 166 | certfilename = NULL; 167 | addcertfilename = NULL; 168 | engine = NULL; 169 | 170 | for (;;) { 171 | int idx; 172 | c = getopt_long(argc, argv, "o:c:k:dvVhe:a:H", options, &idx); 173 | if (c == -1) 174 | break; 175 | 176 | switch (c) { 177 | case 'o': 178 | ctx->outfilename = talloc_strdup(ctx, optarg); 179 | break; 180 | case 'c': 181 | certfilename = optarg; 182 | break; 183 | case 'k': 184 | keyfilename = optarg; 185 | break; 186 | case 'd': 187 | ctx->detached = 1; 188 | break; 189 | case 'v': 190 | ctx->verbose = 1; 191 | break; 192 | case 'V': 193 | version(); 194 | return EXIT_SUCCESS; 195 | case 'h': 196 | usage(); 197 | return EXIT_SUCCESS; 198 | case 'e': 199 | engine = optarg; 200 | break; 201 | case 'a': 202 | addcertfilename = optarg; 203 | break; 204 | case 'H': 205 | hash_only = 1; 206 | break; 207 | } 208 | } 209 | 210 | if (argc != optind + 1) { 211 | usage(); 212 | return EXIT_FAILURE; 213 | } 214 | 215 | ctx->infilename = argv[optind]; 216 | 217 | ctx->image = image_load(ctx->infilename); 218 | if (!ctx->image) 219 | return EXIT_FAILURE; 220 | 221 | if (hash_only) { 222 | unsigned char sha[SHA256_DIGEST_LENGTH]; 223 | image_hash_sha256(ctx->image, sha); 224 | printf("%s\n", sha256_str(sha)); 225 | return EXIT_SUCCESS; 226 | } 227 | 228 | if (!ctx->outfilename) 229 | set_default_outfilename(ctx); 230 | 231 | if (!certfilename) { 232 | fprintf(stderr, 233 | "error: No certificate specified (with --cert)\n"); 234 | usage(); 235 | return EXIT_FAILURE; 236 | } 237 | if (!keyfilename) { 238 | fprintf(stderr, 239 | "error: No key specified (with --key)\n"); 240 | usage(); 241 | return EXIT_FAILURE; 242 | } 243 | 244 | talloc_steal(ctx, ctx->image); 245 | 246 | ERR_load_crypto_strings(); 247 | ERR_load_BIO_strings(); 248 | OpenSSL_add_all_digests(); 249 | OpenSSL_add_all_ciphers(); 250 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 251 | OPENSSL_config(NULL); 252 | #else 253 | OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 254 | #endif 255 | /* here we may get highly unlikely failures or we'll get a 256 | * complaint about FIPS signatures (usually becuase the FIPS 257 | * module isn't present). In either case ignore the errors 258 | * (malloc will cause other failures out lower down */ 259 | ERR_clear_error(); 260 | if (engine) 261 | pkey = fileio_read_engine_key(engine, keyfilename); 262 | else 263 | pkey = fileio_read_pkey(keyfilename); 264 | if (!pkey) 265 | return EXIT_FAILURE; 266 | 267 | X509 *cert = fileio_read_cert(certfilename); 268 | if (!cert) 269 | return EXIT_FAILURE; 270 | 271 | const EVP_MD *md = EVP_get_digestbyname("SHA256"); 272 | 273 | /* set up the PKCS7 object */ 274 | PKCS7 *p7 = PKCS7_new(); 275 | PKCS7_set_type(p7, NID_pkcs7_signed); 276 | 277 | PKCS7_SIGNER_INFO *si = PKCS7_sign_add_signer(p7, cert, 278 | pkey, md, PKCS7_BINARY); 279 | if (!si) { 280 | fprintf(stderr, "error in key/certificate chain\n"); 281 | ERR_print_errors_fp(stderr); 282 | return EXIT_FAILURE; 283 | } 284 | 285 | PKCS7_content_new(p7, NID_pkcs7_data); 286 | 287 | rc = IDC_set(p7, si, ctx->image); 288 | if (rc) 289 | return EXIT_FAILURE; 290 | 291 | if (addcertfilename && add_intermediate_certs(p7, addcertfilename)) 292 | return EXIT_FAILURE; 293 | 294 | sigsize = i2d_PKCS7(p7, NULL); 295 | tmp = buf = talloc_array(ctx->image, uint8_t, sigsize); 296 | i2d_PKCS7(p7, &tmp); 297 | ERR_print_errors_fp(stdout); 298 | 299 | image_add_signature(ctx->image, buf, sigsize); 300 | 301 | if (ctx->detached) { 302 | int i; 303 | uint8_t *buf; 304 | size_t len; 305 | 306 | for (i = 0; !image_get_signature(ctx->image, i, &buf, &len); i++) 307 | ; 308 | image_write_detached(ctx->image, i - 1, ctx->outfilename); 309 | } else 310 | image_write(ctx->image, ctx->outfilename); 311 | 312 | talloc_free(ctx); 313 | 314 | return EXIT_SUCCESS; 315 | } 316 | 317 | -------------------------------------------------------------------------------- /src/sbvarsign.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #define _GNU_SOURCE 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | #include 56 | #include 57 | 58 | #include "efivars.h" 59 | #include "fileio.h" 60 | 61 | static const char *toolname = "sbvarsign"; 62 | 63 | struct varsign_context { 64 | const char *infilename; 65 | const char *outfilename; 66 | 67 | uint8_t *data; 68 | size_t data_len; 69 | 70 | CHAR16 *var_name; 71 | int var_name_bytes; 72 | EFI_GUID var_guid; 73 | uint32_t var_attrs; 74 | 75 | EVP_PKEY *key; 76 | X509 *cert; 77 | 78 | EFI_VARIABLE_AUTHENTICATION_2 *auth_descriptor; 79 | int auth_descriptor_len; 80 | EFI_TIME timestamp; 81 | 82 | int verbose; 83 | }; 84 | 85 | struct attr { 86 | const char *name; 87 | int value; 88 | }; 89 | 90 | #define EFI_VAR_ATTR(n) { #n, EFI_VARIABLE_ ## n } 91 | static struct attr attrs[] = { 92 | EFI_VAR_ATTR(NON_VOLATILE), 93 | EFI_VAR_ATTR(BOOTSERVICE_ACCESS), 94 | EFI_VAR_ATTR(RUNTIME_ACCESS), 95 | EFI_VAR_ATTR(TIME_BASED_AUTHENTICATED_WRITE_ACCESS), 96 | EFI_VAR_ATTR(APPEND_WRITE), 97 | }; 98 | 99 | static uint32_t default_attrs = EFI_VARIABLE_NON_VOLATILE | 100 | EFI_VARIABLE_BOOTSERVICE_ACCESS | 101 | EFI_VARIABLE_RUNTIME_ACCESS | 102 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | 103 | EFI_VARIABLE_APPEND_WRITE; 104 | 105 | static uint32_t attr_invalid = 0xffffffffu; 106 | static const char *attr_prefix = "EFI_VARIABLE_"; 107 | 108 | static const EFI_GUID cert_pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID; 109 | 110 | static void set_default_outfilename(struct varsign_context *ctx) 111 | { 112 | const char *extension = "signed"; 113 | 114 | ctx->outfilename = talloc_asprintf(ctx, "%s.%s", 115 | ctx->infilename, extension); 116 | } 117 | 118 | static uint32_t parse_single_attr(const char *attr_str) 119 | { 120 | unsigned int i; 121 | 122 | /* skip standard prefix, if present */ 123 | if (!strncmp(attr_str, attr_prefix, strlen(attr_prefix))) 124 | attr_str += strlen(attr_prefix); 125 | 126 | for (i = 0; i < ARRAY_SIZE(attrs); i++) { 127 | if (!strcmp(attr_str, attrs[i].name)) 128 | return attrs[i].value; 129 | } 130 | 131 | return attr_invalid; 132 | } 133 | 134 | static uint32_t parse_attrs(const char *attrs_str) 135 | { 136 | uint32_t attr, attrs_val; 137 | const char *attr_str; 138 | char *str; 139 | 140 | /* we always need E_V_T_B_A_W_A */ 141 | attrs_val = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; 142 | 143 | if (!attrs_str[0]) 144 | return attrs_val; 145 | 146 | str = strdup(attrs_str); 147 | 148 | for (attr_str = strtok(str, ","); attr_str; 149 | attr_str = strtok(NULL, ",")) { 150 | 151 | attr = parse_single_attr(attr_str); 152 | if (attr == attr_invalid) { 153 | fprintf(stderr, "Invalid attribute string %s\n", 154 | attr_str); 155 | return attr_invalid; 156 | } 157 | 158 | attrs_val |= attr; 159 | } 160 | 161 | return attrs_val; 162 | } 163 | 164 | static int set_varname(struct varsign_context *ctx, const char *str) 165 | { 166 | CHAR16 *wstr; 167 | int i, len; 168 | 169 | len = strlen(str); 170 | 171 | wstr = talloc_array(ctx, CHAR16, len); 172 | 173 | for (i = 0; i < len; i++) 174 | wstr[i] = str[i]; 175 | 176 | ctx->var_name = wstr; 177 | ctx->var_name_bytes = len * sizeof(CHAR16); 178 | 179 | return 0; 180 | } 181 | 182 | static int parse_guid(const char *str, EFI_GUID *guid) 183 | { 184 | uuid_t uuid; 185 | 186 | if (uuid_parse(str, uuid)) 187 | return -1; 188 | 189 | /* convert to an EFI_GUID */ 190 | guid->Data1 = uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3]; 191 | guid->Data2 = uuid[4] << 8 | uuid[5]; 192 | guid->Data3 = uuid[6] << 8 | uuid[7]; 193 | memcpy(guid->Data4, &uuid[8], sizeof(guid->Data4)); 194 | 195 | return 0; 196 | } 197 | 198 | static int set_timestamp(EFI_TIME *timestamp) 199 | { 200 | struct tm *tm; 201 | time_t t; 202 | 203 | time(&t); 204 | 205 | tm = gmtime(&t); 206 | if (!tm) { 207 | perror("gmtime"); 208 | return -1; 209 | } 210 | 211 | /* copy to our EFI-specific time structure. Other fields (Nanosecond, 212 | * TimeZone, Daylight and Pad) are defined to be zero */ 213 | memset(timestamp, 0, sizeof(*timestamp)); 214 | timestamp->Year = 1900 + tm->tm_year; 215 | timestamp->Month = tm->tm_mon; 216 | timestamp->Day = tm->tm_mday; 217 | timestamp->Hour = tm->tm_hour; 218 | timestamp->Minute = tm->tm_min; 219 | timestamp->Second = tm->tm_sec; 220 | 221 | return 0; 222 | } 223 | 224 | static int add_auth_descriptor(struct varsign_context *ctx) 225 | { 226 | EFI_VARIABLE_AUTHENTICATION_2 *auth; 227 | int rc, len, flags; 228 | EFI_TIME timestamp; 229 | const EVP_MD *md; 230 | BIO *data_bio; 231 | uint8_t *tmp; 232 | PKCS7 *p7; 233 | 234 | if (set_timestamp(×tamp)) 235 | return -1; 236 | 237 | /* create a BIO for our variable data, containing: 238 | * * Variablename (not including trailing nul) 239 | * * VendorGUID 240 | * * Attributes 241 | * * TimeStamp 242 | * * Data 243 | */ 244 | data_bio = BIO_new(BIO_s_mem()); 245 | BIO_write(data_bio, ctx->var_name, ctx->var_name_bytes); 246 | BIO_write(data_bio, &ctx->var_guid, sizeof(ctx->var_guid)); 247 | BIO_write(data_bio, &ctx->var_attrs, sizeof(ctx->var_attrs)); 248 | BIO_write(data_bio, ×tamp, sizeof(timestamp)); 249 | BIO_write(data_bio, ctx->data, ctx->data_len); 250 | 251 | md = EVP_get_digestbyname("SHA256"); 252 | 253 | p7 = PKCS7_new(); 254 | flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOSMIMECAP;; 255 | PKCS7_set_type(p7, NID_pkcs7_signed); 256 | 257 | PKCS7_content_new(p7, NID_pkcs7_data); 258 | 259 | PKCS7_sign_add_signer(p7, ctx->cert, ctx->key, md, flags); 260 | 261 | PKCS7_set_detached(p7, 1); 262 | 263 | rc = PKCS7_final(p7, data_bio, flags); 264 | if (!rc) { 265 | fprintf(stderr, "Error signing variable data\n"); 266 | ERR_print_errors_fp(stderr); 267 | BIO_free_all(data_bio); 268 | return -1; 269 | } 270 | 271 | len = i2d_PKCS7_SIGNED(p7->d.sign, NULL); 272 | 273 | 274 | /* set up our auth descriptor */ 275 | auth = talloc_size(ctx, sizeof(*auth) + len); 276 | 277 | auth->TimeStamp = timestamp; 278 | auth->AuthInfo.Hdr.dwLength = len + sizeof(auth->AuthInfo); 279 | auth->AuthInfo.Hdr.wRevision = 0x0200; 280 | auth->AuthInfo.Hdr.wCertificateType = 0x0EF1; 281 | auth->AuthInfo.CertType = cert_pkcs7_guid; 282 | tmp = auth->AuthInfo.CertData; 283 | i2d_PKCS7_SIGNED(p7->d.sign, &tmp); 284 | 285 | ctx->auth_descriptor = auth; 286 | ctx->auth_descriptor_len = sizeof(*auth) + len; 287 | 288 | BIO_free_all(data_bio); 289 | 290 | return 0; 291 | } 292 | 293 | int write_signed(struct varsign_context *ctx, int include_attrs) 294 | { 295 | int fd, rc; 296 | 297 | fd = open(ctx->outfilename, O_WRONLY | O_CREAT | O_TRUNC, 0644); 298 | if (fd < 0) { 299 | perror("open"); 300 | goto err; 301 | } 302 | 303 | /* For some uses (eg, writing to the efivars filesystem), we may 304 | * want to prefix the signed variable with four bytes of attribute 305 | * data 306 | */ 307 | if (include_attrs) { 308 | rc = write_all(fd, &ctx->var_attrs, sizeof(ctx->var_attrs)); 309 | if (!rc) { 310 | perror("write_all"); 311 | goto err; 312 | } 313 | } 314 | 315 | /* Write the authentication descriptor */ 316 | rc = write_all(fd, ctx->auth_descriptor, ctx->auth_descriptor_len); 317 | if (!rc) { 318 | perror("write_all"); 319 | goto err; 320 | } 321 | 322 | /* ... and the variable data itself */ 323 | rc = write_all(fd, ctx->data, ctx->data_len); 324 | if (!rc) { 325 | perror("write_all"); 326 | goto err; 327 | } 328 | 329 | if (ctx->verbose) { 330 | size_t i = 0; 331 | 332 | printf("Wrote signed data:\n"); 333 | if (include_attrs) { 334 | i = sizeof(ctx->var_attrs); 335 | printf(" [%04lx:%04zx] attrs\n", 0l, i); 336 | } 337 | 338 | printf(" [%04zx:%04x] authentication descriptor\n", 339 | i, ctx->auth_descriptor_len); 340 | 341 | printf(" [%04zx:%04zx] EFI_VAR_AUTH_2 header\n", 342 | i, 343 | sizeof(EFI_VARIABLE_AUTHENTICATION_2)); 344 | 345 | printf(" [%04zx:%04zx] WIN_CERT_UEFI_GUID header\n", 346 | i + offsetof(EFI_VARIABLE_AUTHENTICATION_2, 347 | AuthInfo), 348 | sizeof(WIN_CERTIFICATE_UEFI_GUID)); 349 | 350 | printf(" [%04zx:%04zx] WIN_CERT header\n", 351 | i + offsetof(EFI_VARIABLE_AUTHENTICATION_2, 352 | AuthInfo.Hdr), 353 | sizeof(WIN_CERTIFICATE)); 354 | 355 | printf(" [%04zx:%04zx] pkcs7 data\n", 356 | i + offsetof(EFI_VARIABLE_AUTHENTICATION_2, 357 | AuthInfo.CertData), 358 | ctx->auth_descriptor_len - 359 | sizeof(EFI_VARIABLE_AUTHENTICATION_2)); 360 | 361 | i += ctx->auth_descriptor_len; 362 | 363 | printf(" [%04zx:%04zx] variable data\n", 364 | i, i + ctx->data_len); 365 | } 366 | 367 | close(fd); 368 | return 0; 369 | 370 | err: 371 | fprintf(stderr, "Can't write signed data to file '%s'\n", 372 | ctx->outfilename); 373 | if (fd >= 0) 374 | close(fd); 375 | return -1; 376 | 377 | } 378 | 379 | static void set_default_guid(struct varsign_context *ctx, const char *varname) 380 | { 381 | EFI_GUID secdb_guid = EFI_IMAGE_SECURITY_DATABASE_GUID; 382 | EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; 383 | 384 | if (!strcmp(varname, "db") || !strcmp(varname, "dbx")) 385 | ctx->var_guid = secdb_guid; 386 | else 387 | ctx->var_guid = global_guid; 388 | } 389 | 390 | static struct option options[] = { 391 | { "output", required_argument, NULL, 'o' }, 392 | { "guid", required_argument, NULL, 'g' }, 393 | { "attrs", required_argument, NULL, 'a' }, 394 | { "key", required_argument, NULL, 'k' }, 395 | { "cert", required_argument, NULL, 'c' }, 396 | { "include-attrs", no_argument, NULL, 'i' }, 397 | { "verbose", no_argument, NULL, 'v' }, 398 | { "help", no_argument, NULL, 'h' }, 399 | { "version", no_argument, NULL, 'V' }, 400 | { "engine", required_argument, NULL, 'e'}, 401 | { NULL, 0, NULL, 0 }, 402 | }; 403 | 404 | void usage(void) 405 | { 406 | unsigned int i; 407 | 408 | printf("Usage: %s [options] --key --cert " 409 | " \n" 410 | "Sign a blob of data for use in SetVariable().\n\n" 411 | "Options:\n" 412 | "\t--engine use the specified engine to load the key\n" 413 | "\t--key signing key (PEM-encoded RSA " 414 | "private key)\n" 415 | "\t--cert certificate (x509 certificate)\n" 416 | "\t--include-attrs include attrs at beginning of output file\n" 417 | "\t--guid EFI GUID for the variable. If omitted,\n" 418 | "\t EFI_IMAGE_SECURITY_DATABASE or\n" 419 | "\t EFI_GLOBAL_VARIABLE (depending on\n" 420 | "\t ) will be used.\n" 421 | "\t--attr variable attributes. One or more of:\n", 422 | toolname); 423 | 424 | for (i = 0; i < ARRAY_SIZE(attrs); i++) 425 | printf("\t %s\n", attrs[i].name); 426 | 427 | printf("\t Separate multiple attrs with a comma,\n" 428 | "\t default is all attributes,\n" 429 | "\t TIME_BASED_AUTH... is always included.\n" 430 | "\t--output write signed data to \n" 431 | "\t (default .signed)\n"); 432 | } 433 | 434 | static void version(void) 435 | { 436 | printf("%s %s\n", toolname, VERSION); 437 | } 438 | 439 | int main(int argc, char **argv) 440 | { 441 | const char *guid_str, *attr_str, *varname, *engine; 442 | const char *keyfilename, *certfilename; 443 | struct varsign_context *ctx; 444 | bool include_attrs; 445 | int c; 446 | 447 | ctx = talloc_zero(NULL, struct varsign_context); 448 | 449 | keyfilename = NULL; 450 | certfilename = NULL; 451 | engine = NULL; 452 | guid_str = NULL; 453 | attr_str= NULL; 454 | include_attrs = false; 455 | 456 | for (;;) { 457 | int idx; 458 | c = getopt_long(argc, argv, "o:g:a:k:c:ivVhe:", options, &idx); 459 | if (c == -1) 460 | break; 461 | 462 | switch (c) { 463 | case 'o': 464 | ctx->outfilename = optarg; 465 | break; 466 | case 'g': 467 | guid_str = optarg; 468 | break; 469 | case 'a': 470 | attr_str = optarg; 471 | break; 472 | case 'k': 473 | keyfilename = optarg; 474 | break; 475 | case 'c': 476 | certfilename = optarg; 477 | break; 478 | case 'i': 479 | include_attrs = true; 480 | break; 481 | case 'v': 482 | ctx->verbose = 1; 483 | break; 484 | case 'V': 485 | version(); 486 | return EXIT_SUCCESS; 487 | case 'h': 488 | usage(); 489 | return EXIT_SUCCESS; 490 | case 'e': 491 | engine = optarg; 492 | break; 493 | } 494 | } 495 | 496 | if (argc != optind + 2) { 497 | usage(); 498 | return EXIT_FAILURE; 499 | } 500 | 501 | if (!keyfilename) { 502 | fprintf(stderr, "No signing key specified\n"); 503 | return EXIT_FAILURE; 504 | } 505 | 506 | if (!certfilename) { 507 | fprintf(stderr, "No signing certificate specified\n"); 508 | return EXIT_FAILURE; 509 | } 510 | 511 | /* initialise openssl */ 512 | OpenSSL_add_all_digests(); 513 | OpenSSL_add_all_ciphers(); 514 | ERR_load_crypto_strings(); 515 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 516 | OPENSSL_config(NULL); 517 | #else 518 | OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 519 | #endif 520 | /* here we may get highly unlikely failures or we'll get a 521 | * complaint about FIPS signatures (usually becuase the FIPS 522 | * module isn't present). In either case ignore the errors 523 | * (malloc will cause other failures out lower down */ 524 | ERR_clear_error(); 525 | 526 | /* set up the variable signing context */ 527 | varname = argv[optind]; 528 | set_varname(ctx, varname); 529 | ctx->infilename = argv[optind+1]; 530 | 531 | if (!ctx->outfilename) 532 | set_default_outfilename(ctx); 533 | 534 | if (attr_str) { 535 | ctx->var_attrs = parse_attrs(attr_str); 536 | if (ctx->var_attrs == attr_invalid) 537 | return EXIT_FAILURE; 538 | } else { 539 | ctx->var_attrs = default_attrs; 540 | } 541 | 542 | if (guid_str) { 543 | if (parse_guid(guid_str, &ctx->var_guid)) { 544 | fprintf(stderr, "Invalid GUID '%s'\n", guid_str); 545 | return EXIT_FAILURE; 546 | } 547 | } else { 548 | set_default_guid(ctx, varname); 549 | } 550 | 551 | if (fileio_read_file(ctx, ctx->infilename, &ctx->data, &ctx->data_len)) 552 | return EXIT_FAILURE; 553 | 554 | if (engine) 555 | ctx->key = fileio_read_engine_key(engine, keyfilename); 556 | else 557 | ctx->key = fileio_read_pkey(keyfilename); 558 | if (!ctx->key) 559 | return EXIT_FAILURE; 560 | 561 | ctx->cert = fileio_read_cert(certfilename); 562 | if (!ctx->cert) 563 | return EXIT_FAILURE; 564 | 565 | /* do the signing */ 566 | if (add_auth_descriptor(ctx)) 567 | return EXIT_FAILURE; 568 | 569 | /* write the resulting image */ 570 | if (write_signed(ctx, include_attrs)) 571 | return EXIT_FAILURE; 572 | 573 | return EXIT_SUCCESS; 574 | } 575 | -------------------------------------------------------------------------------- /src/sbverify.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 Jeremy Kerr 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 3 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 17 | * USA. 18 | * 19 | * In addition, as a special exception, the copyright holders give 20 | * permission to link the code of portions of this program with the OpenSSL 21 | * library under certain conditions as described in each individual source file, 22 | * and distribute linked combinations including the two. 23 | * 24 | * You must obey the GNU General Public License in all respects for all 25 | * of the code used other than OpenSSL. If you modify file(s) with this 26 | * exception, you may extend this exception to your version of the 27 | * file(s), but you are not obligated to do so. If you do not wish to do 28 | * so, delete this exception statement from your version. If you delete 29 | * this exception statement from all source files in the program, then 30 | * also delete it here. 31 | */ 32 | #define _GNU_SOURCE 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include "image.h" 48 | #include "idc.h" 49 | #include "fileio.h" 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | 59 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 60 | #define X509_OBJECT_get0_X509(obj) ((obj)->data.x509) 61 | #define X509_OBJECT_get_type(obj) ((obj)->type) 62 | #define X509_STORE_CTX_get0_cert(ctx) ((ctx)->cert) 63 | #define X509_STORE_get0_objects(certs) ((certs)->objs) 64 | #define X509_get_extended_key_usage(cert) ((cert)->ex_xkusage) 65 | #if OPENSSL_VERSION_NUMBER < 0x10020000L 66 | #define X509_STORE_CTX_get0_store(ctx) ((ctx)->ctx) 67 | #endif 68 | #endif 69 | 70 | static const char *toolname = "sbverify"; 71 | static const int cert_name_len = 160; 72 | 73 | enum verify_status { 74 | VERIFY_FAIL = 0, 75 | VERIFY_OK = 1, 76 | }; 77 | 78 | static struct option options[] = { 79 | { "cert", required_argument, NULL, 'c' }, 80 | { "list", no_argument, NULL, 'l' }, 81 | { "detached", required_argument, NULL, 'd' }, 82 | { "verbose", no_argument, NULL, 'v' }, 83 | { "help", no_argument, NULL, 'h' }, 84 | { "version", no_argument, NULL, 'V' }, 85 | { NULL, 0, NULL, 0 }, 86 | }; 87 | 88 | static void usage(void) 89 | { 90 | printf("Usage: %s [options] --cert \n" 91 | "Verify a UEFI secure boot image.\n\n" 92 | "Options:\n" 93 | "\t--cert certificate (x509 certificate)\n" 94 | "\t--list list all signatures (but don't verify)\n" 95 | "\t--detached read signature from , instead of\n" 96 | "\t looking for an embedded signature\n", 97 | toolname); 98 | } 99 | 100 | static void version(void) 101 | { 102 | printf("%s %s\n", toolname, VERSION); 103 | } 104 | 105 | int load_cert(X509_STORE *certs, const char *filename) 106 | { 107 | X509 *cert; 108 | 109 | cert = fileio_read_cert(filename); 110 | if (!cert) 111 | return -1; 112 | 113 | X509_STORE_add_cert(certs, cert); 114 | return 0; 115 | } 116 | 117 | static void print_signature_info(PKCS7 *p7) 118 | { 119 | char subject_name[cert_name_len + 1], issuer_name[cert_name_len + 1]; 120 | PKCS7_SIGNER_INFO *si; 121 | X509 *cert; 122 | int i; 123 | 124 | printf("image signature issuers:\n"); 125 | 126 | for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(p7->d.sign->signer_info); 127 | i++) { 128 | si = sk_PKCS7_SIGNER_INFO_value(p7->d.sign->signer_info, i); 129 | X509_NAME_oneline(si->issuer_and_serial->issuer, 130 | issuer_name, cert_name_len); 131 | printf(" - %s\n", issuer_name); 132 | } 133 | 134 | printf("image signature certificates:\n"); 135 | 136 | for (i = 0; i < sk_X509_num(p7->d.sign->cert); i++) { 137 | cert = sk_X509_value(p7->d.sign->cert, i); 138 | X509_NAME_oneline(X509_get_subject_name(cert), 139 | subject_name, cert_name_len); 140 | X509_NAME_oneline(X509_get_issuer_name(cert), 141 | issuer_name, cert_name_len); 142 | 143 | printf(" - subject: %s\n", subject_name); 144 | printf(" issuer: %s\n", issuer_name); 145 | } 146 | } 147 | 148 | static void print_certificate_store_certs(X509_STORE *certs) 149 | { 150 | char subject_name[cert_name_len + 1], issuer_name[cert_name_len + 1]; 151 | STACK_OF(X509_OBJECT) *objs; 152 | X509_OBJECT *obj; 153 | X509 *cert; 154 | int i; 155 | 156 | printf("certificate store:\n"); 157 | 158 | objs = X509_STORE_get0_objects(certs); 159 | 160 | for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { 161 | obj = sk_X509_OBJECT_value(objs, i); 162 | 163 | if (X509_OBJECT_get_type(obj) != X509_LU_X509) 164 | continue; 165 | 166 | cert = X509_OBJECT_get0_X509(obj); 167 | 168 | X509_NAME_oneline(X509_get_subject_name(cert), 169 | subject_name, cert_name_len); 170 | X509_NAME_oneline(X509_get_issuer_name(cert), 171 | issuer_name, cert_name_len); 172 | 173 | printf(" - subject: %s\n", subject_name); 174 | printf(" issuer: %s\n", issuer_name); 175 | } 176 | } 177 | 178 | static int load_detached_signature_data(struct image *image, 179 | const char *filename, uint8_t **buf, size_t *len) 180 | { 181 | return fileio_read_file(image, filename, buf, len); 182 | } 183 | 184 | static int cert_in_store(X509 *cert, X509_STORE_CTX *ctx) 185 | { 186 | STACK_OF(X509_OBJECT) *objs; 187 | X509_OBJECT *obj; 188 | int i; 189 | 190 | objs = X509_STORE_get0_objects(X509_STORE_CTX_get0_store(ctx)); 191 | 192 | for (i = 0; i < sk_X509_OBJECT_num(objs); i++) { 193 | obj = sk_X509_OBJECT_value(objs, i); 194 | 195 | if (X509_OBJECT_get_type(obj) == X509_LU_X509 && 196 | !X509_cmp(X509_OBJECT_get0_X509(obj), cert)) 197 | return 1; 198 | } 199 | 200 | return 0; 201 | } 202 | 203 | static int x509_verify_cb(int status, X509_STORE_CTX *ctx) 204 | { 205 | int err = X509_STORE_CTX_get_error(ctx); 206 | 207 | /* also accept code-signing keys */ 208 | if (err == X509_V_ERR_INVALID_PURPOSE && 209 | X509_get_extended_key_usage(X509_STORE_CTX_get0_cert(ctx)) 210 | == XKU_CODE_SIGN) 211 | status = 1; 212 | 213 | else if (err == X509_V_ERR_CERT_UNTRUSTED || 214 | err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT || 215 | err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) { 216 | /* all certs given with the --cert argument are trusted */ 217 | 218 | if (cert_in_store(X509_STORE_CTX_get_current_cert(ctx), ctx)) 219 | status = 1; 220 | } else if (err == X509_V_ERR_CERT_HAS_EXPIRED || 221 | err == X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD || 222 | err == X509_V_ERR_CERT_NOT_YET_VALID || 223 | err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || 224 | err == X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD) 225 | /* UEFI explicitly allows expired certificates */ 226 | status = 1; 227 | 228 | return status; 229 | } 230 | 231 | int main(int argc, char **argv) 232 | { 233 | const char *detached_sig_filename, *image_filename; 234 | enum verify_status status; 235 | int rc, c, flags, list; 236 | const uint8_t *tmp_buf; 237 | struct image *image; 238 | X509_STORE *certs; 239 | uint8_t *sig_buf; 240 | size_t sig_size; 241 | struct idc *idc; 242 | int verbose; 243 | BIO *idcbio; 244 | PKCS7 *p7; 245 | int sig_count = 0; 246 | 247 | status = VERIFY_FAIL; 248 | certs = X509_STORE_new(); 249 | list = 0; 250 | verbose = 0; 251 | detached_sig_filename = NULL; 252 | 253 | OpenSSL_add_all_digests(); 254 | ERR_load_crypto_strings(); 255 | #if OPENSSL_VERSION_NUMBER < 0x10100000L 256 | OPENSSL_config(NULL); 257 | #else 258 | OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL); 259 | #endif 260 | /* here we may get highly unlikely failures or we'll get a 261 | * complaint about FIPS signatures (usually becuase the FIPS 262 | * module isn't present). In either case ignore the errors 263 | * (malloc will cause other failures out lower down */ 264 | ERR_clear_error(); 265 | 266 | for (;;) { 267 | int idx; 268 | c = getopt_long(argc, argv, "c:d:lvVh", options, &idx); 269 | if (c == -1) 270 | break; 271 | 272 | switch (c) { 273 | case 'c': 274 | rc = load_cert(certs, optarg); 275 | if (rc) 276 | return EXIT_FAILURE; 277 | break; 278 | case 'd': 279 | detached_sig_filename = optarg; 280 | break; 281 | case 'l': 282 | list = 1; 283 | break; 284 | case 'v': 285 | verbose++; 286 | break; 287 | case 'V': 288 | version(); 289 | return EXIT_SUCCESS; 290 | case 'h': 291 | usage(); 292 | return EXIT_SUCCESS; 293 | } 294 | 295 | } 296 | 297 | if (argc != optind + 1) { 298 | usage(); 299 | return EXIT_FAILURE; 300 | } 301 | 302 | image_filename = argv[optind]; 303 | 304 | image = image_load(image_filename); 305 | if (!image) { 306 | fprintf(stderr, "Can't open image %s\n", image_filename); 307 | return EXIT_FAILURE; 308 | } 309 | 310 | for (;;) { 311 | if (detached_sig_filename) { 312 | if (sig_count++) 313 | break; 314 | 315 | rc = load_detached_signature_data(image, detached_sig_filename, 316 | &sig_buf, &sig_size); 317 | } else 318 | rc = image_get_signature(image, sig_count++, &sig_buf, &sig_size); 319 | 320 | if (rc) { 321 | if (sig_count == 0) { 322 | fprintf(stderr, "Unable to read signature data from %s\n", 323 | detached_sig_filename ? : image_filename); 324 | } 325 | break; 326 | } 327 | 328 | tmp_buf = sig_buf; 329 | if (verbose || list) 330 | printf("signature %d\n", sig_count); 331 | p7 = d2i_PKCS7(NULL, &tmp_buf, sig_size); 332 | if (!p7) { 333 | fprintf(stderr, "Unable to parse signature data\n"); 334 | ERR_print_errors_fp(stderr); 335 | break; 336 | } 337 | 338 | if (verbose || list) { 339 | print_signature_info(p7); 340 | if (verbose > 1) 341 | print_certificate_store_certs(certs); 342 | } 343 | 344 | if (list) 345 | continue; 346 | 347 | idcbio = BIO_new(BIO_s_mem()); 348 | idc = IDC_get(p7, idcbio); 349 | if (!idc) { 350 | fprintf(stderr, "Unable to get IDC from PKCS7\n"); 351 | break; 352 | } 353 | 354 | rc = IDC_check_hash(idc, image); 355 | if (rc) { 356 | fprintf(stderr, "Image fails hash check\n"); 357 | break; 358 | } 359 | 360 | flags = PKCS7_BINARY; 361 | 362 | /* OpenSSL 1.0.2e no longer allows calling PKCS7_verify with 363 | * both data and content. Empty out the content. */ 364 | p7->d.sign->contents->d.ptr = NULL; 365 | 366 | X509_STORE_set_verify_cb_func(certs, x509_verify_cb); 367 | rc = PKCS7_verify(p7, NULL, certs, idcbio, NULL, flags); 368 | if (rc) { 369 | if (verbose) 370 | printf("PKCS7 verification passed\n"); 371 | 372 | status = VERIFY_OK; 373 | } else if (verbose) { 374 | printf("PKCS7 verification failed\n"); 375 | ERR_print_errors_fp(stderr); 376 | } 377 | 378 | } 379 | 380 | talloc_free(image); 381 | 382 | if (list) 383 | exit(EXIT_SUCCESS); 384 | 385 | if (status == VERIFY_OK) 386 | printf("Signature verification OK\n"); 387 | else 388 | printf("Signature verification failed\n"); 389 | 390 | return status == VERIFY_OK ? EXIT_SUCCESS : EXIT_FAILURE; 391 | } 392 | -------------------------------------------------------------------------------- /src/verify.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "image.h" 6 | 7 | int main(int argc, char **argv) 8 | { 9 | return EXIT_SUCCESS; 10 | } 11 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | AUTOMAKE_OPTIONS = parallel-tests 3 | 4 | test_key = private-key.rsa 5 | test_cert = public-cert.pem 6 | ca_key = ca-key.ec 7 | ca_cert = ca-cert.pem 8 | int_key = int-key.ec 9 | int_cert = int-cert.pem 10 | test_arches = $(EFI_ARCH) 11 | 12 | check_PROGRAMS = test.pecoff 13 | 14 | # override the automake rule to say we build from .elf files 15 | test.pecoff$(EXEEXT): test.elf 16 | 17 | if TEST_BINARY_FORMAT 18 | EFILDFLAGS = --defsym=EFI_SUBSYSTEM=0x0a 19 | FORMAT = -O binary 20 | else 21 | FORMAT = --target=efi-app-$(EFI_ARCH) 22 | endif 23 | check_DATA = $(test_key) $(test_cert) 24 | check_SCRIPTS = test-wrapper.sh 25 | 26 | .elf.pecoff: 27 | echo "TEST ARCHES $(test_arches) TEST_COMPAT=$(TEST_COMPAT_FALSE)" 28 | $(OBJCOPY) -j .text -j .sdata -j .data \ 29 | -j .dynamic -j .dynsym -j .rel \ 30 | -j .rela -j .reloc \ 31 | $(FORMAT) $^ $@ 32 | 33 | .$(OBJEXT).elf: 34 | $(LD) $(EFILDFLAGS) -nostdlib -L /usr/lib -L /usr/lib64 -L $(CRTPATH) -shared -Bsymbolic $(CRTPATH)/crt0-efi-$(EFI_ARCH).o -T elf_$(EFI_ARCH)_efi.lds $< -o $@ -lefi -lgnuefi 35 | 36 | AM_CFLAGS=-fpic -I/usr/include/efi -I/usr/include/efi/$(EFI_ARCH) 37 | 38 | %.rsa: Makefile 39 | openssl genrsa -out $@ 2048 40 | 41 | %.ec: Makefile 42 | openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:prime256v1 -out $@ 43 | 44 | $(ca_cert): $(ca_key) Makefile 45 | openssl req -x509 -days 1 -sha256 -subj '/CN=CA Key/' -new -key $< -out $@ 46 | 47 | $(int_cert): $(int_key) $(ca_cert) Makefile 48 | openssl req -new -subj '/CN=Intermediate Certificate/' -key $< -out tmp.req 49 | echo -e "[ca]\nbasicConstraints = critical, CA:true\n" > ca.cnf 50 | openssl x509 -req -sha256 -CA $(ca_cert) -CAkey $(ca_key) -in tmp.req -set_serial 1 -days 1 -extfile ca.cnf -extensions ca -out $@ 51 | -rm -f tmp.req ca.cnf 52 | 53 | $(test_cert): $(test_key) $(int_cert) Makefile 54 | openssl req -new -subj '/CN=Signer Certificate/' -key $< -out tmp.req 55 | openssl x509 -req -sha256 -CA $(int_cert) -CAkey $(int_key) -in tmp.req -set_serial 1 -days 1 -out $@ 56 | -rm -f tmp.req 57 | 58 | TESTS = sign-verify.sh \ 59 | sign-verify-detached.sh \ 60 | sign-detach-verify.sh \ 61 | sign-attach-verify.sh \ 62 | sign-missing-image.sh \ 63 | sign-missing-cert.sh \ 64 | sign-missing-key.sh \ 65 | verify-missing-image.sh \ 66 | verify-missing-cert.sh \ 67 | sign-invalidattach-verify.sh \ 68 | resign-warning.sh \ 69 | reattach-warning.sh 70 | 71 | if !TEST_BINARY_FORMAT 72 | ## 73 | # These tests involve objdump which will fail because the format 74 | # is not recognised. Someone needs to fix arm bfd to add efi 75 | ## 76 | TESTS += cert-table-header.sh \ 77 | detach-remove.sh 78 | endif 79 | 80 | 81 | TEST_EXTENSIONS = .sh 82 | AM_TESTS_ENVIRONMENT = TEST_ARCHES='$(test_arches)'; export TEST_ARCHES; 83 | SH_LOG_COMPILER = $(srcdir)/test-wrapper.sh 84 | 85 | EXTRA_DIST = test.S $(TESTS) $(check_SCRIPTS) 86 | CLEANFILES = $(test_key) $(test_cert) $(int_key) $(int_cert) $(ca_key) \ 87 | $(ca_cert) 88 | -------------------------------------------------------------------------------- /tests/cert-table-header.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Parse the data directory of a PE/COFF file and returns two hex values: 4 | # the file offset and size of the signature table. 5 | function sigtable_params() { 6 | filename="$1" 7 | objdump -p "$filename" | awk '/^Entry 4/ {print "0x"$3 " " "0x"$4}' 8 | } 9 | 10 | # Extract the signature from a file containing a signature table, 11 | # and write to stdout 12 | function extract_sig() { 13 | filename="$1" 14 | cert_table_header_size=8 15 | 16 | params=($(hexdump -n$cert_table_header_size \ 17 | -e '/4 "%u " /2 "%04x " /2 "%04x\n"' \ 18 | "$filename")) 19 | cert_size=${params[0]} 20 | cert_revision=${params[1]} 21 | cert_type=${params[2]} 22 | 23 | # check type & revision 24 | [ "$cert_revision" -eq '0200' ] 25 | [ "$cert_type" -eq '0002' ] 26 | 27 | dd if="$filename" bs=1 skip=$cert_table_header_size \ 28 | count=$(($cert_size - $cert_table_header_size)) 2>/dev/null 29 | } 30 | 31 | function repeat() { 32 | str=$1 33 | count=$2 34 | for (( i = 0; $i < $count; i++ )) 35 | do 36 | echo -n "$str" 37 | done 38 | } 39 | 40 | cert="test.cert" 41 | signed="test.signed" 42 | 43 | for i in {1..8} 44 | do 45 | # generate a variable-length parameter for the certificate subject 46 | subj="/CN=$(repeat 'x' $i)" 47 | 48 | # create a temporary cert, and sign the image with it 49 | openssl req -x509 -sha256 -subj "$subj" -new -key "$key" -out "$cert" 50 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" 51 | 52 | # extract the sigtable 53 | params=($(sigtable_params "$signed")) 54 | 55 | # split and convert to base-10 56 | sigtable_offset=$((${params[0]})) 57 | sigtable_size=$((${params[1]})) 58 | 59 | # check that we have a correctly-padded sigtable 60 | [ $(($sigtable_size % 8)) -eq 0 ] 61 | 62 | sigtable='test.sigtable' 63 | 64 | dd if="$signed" bs=1 skip=$sigtable_offset count=$sigtable_size \ 65 | of=$sigtable 2>/dev/null 66 | 67 | # extract sig, and feed to openssl's PKCS7 parser 68 | extract_sig "$sigtable" | openssl pkcs7 -inform DER -noout 69 | done 70 | -------------------------------------------------------------------------------- /tests/detach-remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | signed="test.signed" 4 | unsigned="test.unsigned" 5 | 6 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" 7 | cp "$signed" "$unsigned" 8 | "$sbattach" --remove "$unsigned" 9 | 10 | # ensure that there is no security directory 11 | objdump -p $unsigned | grep -q '0\+ 0\+ Security Directory' 12 | 13 | ## 14 | # somewhat tricky: i386 pecoff binaries can be too short, so we add padding 15 | # when signing, so make sure the sizes match modulo the padding 16 | ## 17 | # ensure that the unsigned file is the same size as our original binary 18 | [ $(( ($(stat --format=%s "$image")+7)&~7)) -eq $(( ($(stat --format=%s "$unsigned")+7)&~7)) ] 19 | 20 | -------------------------------------------------------------------------------- /tests/reattach-warning.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | ## 3 | # The original warning is gone because we now do multiple signatures 4 | # instead check that the second signature is added 5 | ## 6 | 7 | signed="test.signed" 8 | sig="test.sig" 9 | 10 | "$sbsign" --cert "$cert" --key "$key" --detached --output "$sig" "$image" 11 | cp "$image" "$signed" 12 | "$sbattach" --attach "$sig" "$signed" 13 | "$sbattach" --attach "$sig" "$signed" 2>&1 | 14 | grep '^Image was already signed; adding additional signature' 15 | -------------------------------------------------------------------------------- /tests/resign-warning.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | ## 3 | # The original warning is gone because we now do multiple signatures 4 | # instead check that the second signature is added 5 | ## 6 | 7 | signed="test.signed" 8 | 9 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" 10 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$signed" 2>&1 | 11 | grep '^Image was already signed; adding additional signature' 12 | -------------------------------------------------------------------------------- /tests/sign-attach-verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | sig="test.sig" 4 | signed="test.signed" 5 | 6 | "$sbsign" --cert "$cert" --key "$key" --detached --output "$sig" "$image" || exit 1 7 | cp "$image" "$signed" || exit 1 8 | "$sbattach" --attach "$sig" "$signed" || exit 1 9 | "$sbverify" --cert "$cert" "$signed" || exit 1 10 | "$sbverify" --cert "$intcert" "$signed" || exit 1 11 | # there's no intermediate cert in the image so it can't chain to the ca which 12 | # is why this should fail 13 | "$sbverify" --cert "$cacert" "$signed" && exit 1 14 | 15 | # now add intermediates 16 | "$sbsign" --cert "$cert" --key "$key" --addcert "$intcert" --detached --output "$sig" "$image" || exit 1 17 | cp "$image" "$signed" || exit 1 18 | "$sbattach" --attach "$sig" "$signed" || exit 1 19 | "$sbverify" --cert "$cert" "$signed" || exit 1 20 | "$sbverify" --cert "$intcert" "$signed" || exit 1 21 | "$sbverify" --cert "$cacert" "$signed" || exit 1 22 | -------------------------------------------------------------------------------- /tests/sign-detach-verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | signed="test.signed" 4 | sig="test.sig" 5 | 6 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" 7 | "$sbattach" --detach "$sig" "$signed" 8 | "$sbverify" --cert "$cert" --detached $sig "$image" 9 | -------------------------------------------------------------------------------- /tests/sign-invalidattach-verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | invsig="test.invsig" 4 | dd if=/dev/zero of="$invsig" bs=1 count=1k 5 | tmp_image=test.pecoff 6 | cp "$image" "$tmp_image" 7 | 8 | set +e 9 | "$sbattach" --attach "$invsig" "$tmp_image" 10 | rc=$? 11 | set -e 12 | 13 | test $rc -eq 1 14 | -------------------------------------------------------------------------------- /tests/sign-missing-cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | signed="test.signed" 4 | 5 | set +e 6 | "$sbsign" --cert "missing-cert" --key "$key" --output "$signed" "$image" 7 | rc=$? 8 | set -e 9 | 10 | test $rc -eq 1 11 | -------------------------------------------------------------------------------- /tests/sign-missing-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | signed="test.signed" 4 | 5 | set +e 6 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "missing-image" 7 | rc=$? 8 | set -e 9 | 10 | test $rc -eq 1 11 | -------------------------------------------------------------------------------- /tests/sign-missing-key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | signed="test.signed" 4 | 5 | set +e 6 | "$sbsign" --cert "$cert" --key "missing-key" --output "$signed" "$image" 7 | rc=$? 8 | set -e 9 | 10 | test $rc -eq 1 11 | -------------------------------------------------------------------------------- /tests/sign-verify-detached.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | sig="test.sig" 4 | 5 | "$sbsign" --cert "$cert" --key "$key" --detached --output $sig "$image" || exit 1 6 | "$sbverify" --cert "$cert" --detached $sig "$image" || exit 1 7 | "$sbverify" --cert "$intcert" --detached $sig "$image" || exit 1 8 | # should fail because no intermediate 9 | "$sbverify" --cert "$cacert" --detached $sig "$image" && exit 1 10 | 11 | # now make sure everything succeeds with the intermediate added 12 | "$sbsign" --cert "$cert" --key "$key" --addcert "$intcert" --detached --output $sig "$image" || exit 1 13 | "$sbverify" --cert "$cert" --detached $sig "$image" || exit 1 14 | "$sbverify" --cert "$intcert" --detached $sig "$image" || exit 1 15 | "$sbverify" --cert "$cacert" --detached $sig "$image" || exit 1 16 | 17 | exit 0 18 | -------------------------------------------------------------------------------- /tests/sign-verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | signed="test.signed" 4 | 5 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" || exit 1 6 | "$sbverify" --cert "$cert" "$signed" || exit 1 7 | "$sbverify" --cert "$intcert" "$signed" || exit 1 8 | # there's no intermediate cert in the image so it can't chain to the ca which 9 | # is why this should fail 10 | "$sbverify" --cert "$cacert" "$signed" && exit 1 11 | 12 | # now add the intermediates and each level should succeed 13 | "$sbsign" --cert "$cert" --addcert "$intcert" --key "$key" --output "$signed" "$image" || exit 1 14 | "$sbverify" --cert "$cert" "$signed" || exit 1 15 | "$sbverify" --cert "$intcert" "$signed" || exit 1 16 | "$sbverify" --cert "$cacert" "$signed" || exit 1 17 | 18 | -------------------------------------------------------------------------------- /tests/test-wrapper.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # set a few global variables that may be used by the test 4 | basedir=$(cd $srcdir && pwd) 5 | datadir=$(pwd) 6 | bindir="$datadir/../src" 7 | 8 | sbsign=$bindir/sbsign 9 | sbverify=$bindir/sbverify 10 | sbattach=$bindir/sbattach 11 | 12 | key="$datadir/private-key.rsa" 13 | cert="$datadir/public-cert.pem" 14 | intkey="$datadir/int-key.ec" 15 | intcert="$datadir/int-cert.pem" 16 | cakey="$datadir/ca-key.ec" 17 | cacert="$datadir/ca-cert.pem" 18 | 19 | export basedir datadir bindir sbsign sbverify sbattach key cert intkey intcert cakey cacert 20 | 21 | # 'test' needs to be an absolute path, as we will cd to a temporary 22 | # directory before running the test 23 | test="$PWD/$1" 24 | rc=0 25 | 26 | function run_test() 27 | { 28 | test="$1" 29 | 30 | # image depends on the test arch 31 | image="$datadir/test.pecoff" 32 | export image 33 | 34 | # create the temporary directory... 35 | tempdir=$(mktemp --directory) 36 | 37 | # ... and run the test in it. 38 | ( cd "$tempdir"; $test ) 39 | 40 | if [ $? -ne 0 ] 41 | then 42 | echo "test $(basename $test) failed on arch $arch" 43 | echo 44 | rc=1 45 | fi 46 | 47 | rm -rf "$tempdir" 48 | } 49 | 50 | # run test on all available arches 51 | for arch in $TEST_ARCHES 52 | do 53 | run_test $test 54 | done 55 | 56 | exit $rc 57 | -------------------------------------------------------------------------------- /tests/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | EFI_STATUS 5 | efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) 6 | { 7 | return EFI_SUCCESS; 8 | } 9 | -------------------------------------------------------------------------------- /tests/verify-missing-cert.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | signed="test.signed" 4 | 5 | "$sbsign" --cert "$cert" --key "$key" --output "$signed" "$image" 6 | 7 | set +e 8 | "$sbverify" --cert "missing-cert" "$signed" 9 | rc=$? 10 | set -e 11 | 12 | test $rc -eq 1 13 | -------------------------------------------------------------------------------- /tests/verify-missing-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | signed="test.signed" 4 | 5 | set +e 6 | "$sbverify" "missing-image" 7 | rc=$? 8 | set -e 9 | 10 | test $rc -eq 1 11 | --------------------------------------------------------------------------------