diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-08 16:00:35 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-04-08 16:00:35 +0000 |
commit | 0ae9e5c7f7099ff3dba8fe2f022c8eef35e083ca (patch) | |
tree | 1e00499c0bed9db81feab51bbd69f4652a2a82ad | |
parent | d6d41274a251064b52a9ccb8e9d9f8a9890df8bc (diff) | |
parent | cc5e51366174ddd4580c78c9845d86e44586c034 (diff) | |
download | fsverity-utils-aml_tz2_305400100.tar.gz |
Snap for 8426163 from cc5e51366174ddd4580c78c9845d86e44586c034 to mainline-tzdata2-releaseandroid-mainline-12.0.0_r112aml_tz2_305400500aml_tz2_305400300aml_tz2_305400100aml_tz2_304500300aml_tz2_303900110aml_tz2_303900102aml_tz2_303800002aml_tz2_303800001aml_tz2_303200001android12-mainline-tzdata2-releaseaml_tz2_305400100
Change-Id: I7064b1f27db92266d43ad2ddc064b5fca192456d
-rw-r--r-- | .clang-format | 17 | ||||
-rw-r--r-- | .gitignore | 12 | ||||
-rw-r--r-- | Android.bp | 68 | ||||
-rw-r--r-- | COPYING | 339 | ||||
-rw-r--r-- | LICENSE | 360 | ||||
-rw-r--r-- | METADATA | 11 | ||||
-rw-r--r-- | MODULE_LICENSE_GPL (renamed from MODULE_LICENSE_MIT) | 0 | ||||
-rw-r--r-- | Makefile | 261 | ||||
-rw-r--r-- | NEWS.md | 43 | ||||
-rw-r--r-- | NOTICE | 339 | ||||
-rw-r--r-- | README.md | 114 | ||||
-rw-r--r-- | cmd_enable.c (renamed from programs/cmd_enable.c) | 77 | ||||
-rw-r--r-- | cmd_measure.c (renamed from programs/cmd_measure.c) | 24 | ||||
-rw-r--r-- | cmd_sign.c | 635 | ||||
-rw-r--r-- | commands.h | 24 | ||||
-rw-r--r-- | common/fsverity_uapi.h | 91 | ||||
-rw-r--r-- | common/win32_defs.h | 57 | ||||
-rw-r--r-- | fsverity.c (renamed from programs/fsverity.c) | 117 | ||||
-rw-r--r-- | fsverity_uapi.h | 40 | ||||
-rw-r--r-- | hash_algs.c (renamed from lib/hash_algs.c) | 135 | ||||
-rw-r--r-- | hash_algs.h | 68 | ||||
-rw-r--r-- | include/libfsverity.h | 213 | ||||
-rw-r--r-- | lib/compute_digest.c | 238 | ||||
-rw-r--r-- | lib/enable.c | 53 | ||||
-rw-r--r-- | lib/lib_private.h | 95 | ||||
-rw-r--r-- | lib/libfsverity.pc.in | 10 | ||||
-rw-r--r-- | lib/sign_digest.c | 390 | ||||
-rw-r--r-- | lib/utils.c | 132 | ||||
-rw-r--r-- | programs/cmd_digest.c | 129 | ||||
-rw-r--r-- | programs/cmd_sign.c | 133 | ||||
-rw-r--r-- | programs/fsverity.h | 58 | ||||
-rw-r--r-- | programs/test_compute_digest.c | 310 | ||||
-rw-r--r-- | programs/test_hash_algs.c | 45 | ||||
-rw-r--r-- | programs/test_sign_digest.c | 57 | ||||
-rw-r--r-- | programs/utils.h | 51 | ||||
-rwxr-xr-x | scripts/do-release.sh | 46 | ||||
-rwxr-xr-x | scripts/run-sparse.sh | 14 | ||||
-rwxr-xr-x | scripts/run-tests.sh | 187 | ||||
-rw-r--r-- | testdata/cert.pem | 31 | ||||
-rw-r--r-- | testdata/file.sig | bin | 708 -> 0 bytes | |||
-rw-r--r-- | testdata/key.pem | 52 | ||||
-rw-r--r-- | util.c (renamed from programs/utils.c) | 52 | ||||
-rw-r--r-- | util.h (renamed from common/common_defs.h) | 58 |
43 files changed, 2068 insertions, 3118 deletions
diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 834d0a4..0000000 --- a/.clang-format +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: MIT -# Copyright 2020 Google LLC -# -# Use of this source code is governed by an MIT-style -# license that can be found in the LICENSE file or at -# https://opensource.org/licenses/MIT. - -# Formatting settings to approximate the Linux kernel coding style. -BasedOnStyle: LLVM -AllowShortFunctionsOnASingleLine: false -AllowShortIfStatementsOnASingleLine: false -BreakBeforeBraces: Linux -Cpp11BracedListStyle: false -IncludeBlocks: Preserve -IndentCaseLabels: false -IndentWidth: 8 -UseTab: Always @@ -1,13 +1,5 @@ -*.a +fsverity *.o -*.patch -*.so -*.so.* -/.build-config -/fsverity -/fsverity.sig -/run-tests.log -/test_* +tags cscope.* ncscope.* -tags @@ -1,69 +1,11 @@ -package { - default_applicable_licenses: ["external_fsverity-utils_license"], -} - -// Added automatically by a large-scale-change that took the approach of -// 'apply every license found to every target'. While this makes sure we respect -// every license restriction, it may not be entirely correct. -// -// e.g. GPL in an MIT project might only apply to the contrib/ directory. -// -// Please consider splitting the single license below into multiple licenses, -// taking care not to lose any license_kind information, and overriding the -// default license using the 'licenses: [...]' property on targets as needed. -// -// For unused files, consider creating a 'fileGroup' with "//visibility:private" -// to attach the license to, and including a comment whether the files may be -// used in the current project. -// See: http://go/android-license-faq -license { - name: "external_fsverity-utils_license", - visibility: [":__subpackages__"], - license_kinds: [ - "SPDX-license-identifier-GPL-2.0", - "SPDX-license-identifier-MIT", - ], - license_text: [ - "LICENSE", - ], -} - -cc_defaults { - name: "fsverity_default_flags", - - cflags: [ - "-Wall", - "-Wno-pointer-arith", - "-D_GNU_SOURCE", - "-D_FILE_OFFSET_BITS=64", - ], -} - cc_binary { name: "fsverity", - defaults: [ - "fsverity_default_flags", - ], - host_supported: true, - shared_libs: ["libfsverity"], - srcs: [ - "programs/cmd_*.c", - "programs/fsverity.c", - "programs/utils.c", - ], -} - -cc_library { - name: "libfsverity", - defaults: [ - "fsverity_default_flags", - ], host_supported: true, shared_libs: ["libcrypto"], - - export_include_dirs: ["include"], - - srcs: [ - "lib/*.c", + cflags: [ + "-Wall", + "-Wno-pointer-arith", + "-D_FILE_OFFSET_BITS=64" ], + srcs: ["*.c"], } @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. @@ -1,21 +1,339 @@ -Copyright 2019 the fsverity-utils authors - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation files -(the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. @@ -1,16 +1,15 @@ name: "fsverity-utils" -description: "This is fsverity-utils, a set of userspace utilities for fs-verity. fs-verity is a Linux kernel feature that does transparent on-demand integrity/authenticity verification of the contents of read-only files, using a hidden Merkle tree (hash tree) associated with the file. fsverity-utils currently contains just one program, `fsverity`. The `fsverity` program allows you to set up fs-verity protected files." +description: "This is `fsverity`, a userspace utility for fs-verity. fs-verity is a Linux kernel feature that does transparent on-demand integrity/authenticity verification of the contents of read-only files, using a Merkle tree (hash tree) hidden after the end of the file. The mechanism is similar to dm-verity, but implemented at the file level rather than at the block device level. The `fsverity` utility allows you to set up fs-verity protected files." third_party { url { type: GIT value: "https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/fsverity-utils.git" } - version: "v1.3" - # would be NOTICE save for common/fsverity_uapi.h + version: "2151209ce1dae61c4ee7480e2c39ada1d912fcb2" license_type: RESTRICTED last_upgrade_date { - year: 2021 - month: 1 - day: 19 + year: 2019 + month: 7 + day: 24 } } diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_GPL index e69de29..e69de29 100644 --- a/MODULE_LICENSE_MIT +++ b/MODULE_LICENSE_GPL @@ -1,253 +1,22 @@ -# SPDX-License-Identifier: MIT -# Copyright 2020 Google LLC -# -# Use of this source code is governed by an MIT-style -# license that can be found in the LICENSE file or at -# https://opensource.org/licenses/MIT. +EXE := fsverity +CFLAGS := -O2 -Wall +CPPFLAGS := -D_FILE_OFFSET_BITS=64 +LDLIBS := -lcrypto +DESTDIR := /usr/local +SRC := $(wildcard *.c) +OBJ := $(SRC:.c=.o) +HDRS := $(wildcard *.h) +all:$(EXE) -# Use 'make help' to list available targets. -# -# Define V=1 to enable "verbose" mode, showing all executed commands. -# -# Define USE_SHARED_LIB=1 to link the fsverity binary to the shared library -# libfsverity.so rather than to the static library libfsverity.a. -# -# Define PREFIX to override the installation prefix, like './configure --prefix' -# in autotools-based projects (default: /usr/local) -# -# Define BINDIR to override where to install binaries, like './configure -# --bindir' in autotools-based projects (default: PREFIX/bin) -# -# Define INCDIR to override where to install headers, like './configure -# --includedir' in autotools-based projects (default: PREFIX/include) -# -# Define LIBDIR to override where to install libraries, like './configure -# --libdir' in autotools-based projects (default: PREFIX/lib) -# -# Define DESTDIR to override the installation destination directory -# (default: empty string) -# -# You can also specify custom CC, CFLAGS, CPPFLAGS, LDFLAGS, and/or PKGCONF. -# -############################################################################## +$(EXE):$(OBJ) -cc-option = $(shell if $(CC) $(1) -c -x c /dev/null -o /dev/null > /dev/null 2>&1; \ - then echo $(1); fi) +$(OBJ): %.o: %.c $(HDRS) -# Support building with MinGW for minimal Windows fsverity.exe, but not for -# libfsverity. fsverity.exe will be statically linked. -ifneq ($(findstring -mingw,$(shell $(CC) -dumpmachine 2>/dev/null)),) -MINGW = 1 -endif - -CFLAGS ?= -O2 - -override CFLAGS := -Wall -Wundef \ - $(call cc-option,-Wdeclaration-after-statement) \ - $(call cc-option,-Wimplicit-fallthrough) \ - $(call cc-option,-Wmissing-field-initializers) \ - $(call cc-option,-Wmissing-prototypes) \ - $(call cc-option,-Wstrict-prototypes) \ - $(call cc-option,-Wunused-parameter) \ - $(call cc-option,-Wvla) \ - $(CFLAGS) - -override CPPFLAGS := -Iinclude -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(CPPFLAGS) - -ifneq ($(V),1) -QUIET_CC = @echo ' CC ' $@; -QUIET_CCLD = @echo ' CCLD ' $@; -QUIET_AR = @echo ' AR ' $@; -QUIET_LN = @echo ' LN ' $@; -QUIET_GEN = @echo ' GEN ' $@; -endif -USE_SHARED_LIB ?= -PREFIX ?= /usr/local -BINDIR ?= $(PREFIX)/bin -INCDIR ?= $(PREFIX)/include -LIBDIR ?= $(PREFIX)/lib -DESTDIR ?= -ifneq ($(MINGW),1) -PKGCONF ?= pkg-config -else -PKGCONF := false -EXEEXT := .exe -endif -FSVERITY := fsverity$(EXEEXT) - -# Rebuild if a user-specified setting that affects the build changed. -.build-config: FORCE - @flags=$$( \ - echo 'CC=$(CC)'; \ - echo 'CFLAGS=$(CFLAGS)'; \ - echo 'CPPFLAGS=$(CPPFLAGS)'; \ - echo 'LDFLAGS=$(LDFLAGS)'; \ - echo 'LDLIBS=$(LDLIBS)'; \ - echo 'USE_SHARED_LIB=$(USE_SHARED_LIB)'; \ - ); \ - if [ "$$flags" != "`cat $@ 2>/dev/null`" ]; then \ - [ -e $@ ] && echo "Rebuilding due to new settings"; \ - echo "$$flags" > $@; \ - fi - -DEFAULT_TARGETS := -COMMON_HEADERS := $(wildcard common/*.h) -LDLIBS := $(shell "$(PKGCONF)" libcrypto --libs 2>/dev/null || echo -lcrypto) -CFLAGS += $(shell "$(PKGCONF)" libcrypto --cflags 2>/dev/null || echo) - -# If we are dynamically linking, when running tests we need to override -# LD_LIBRARY_PATH as no RPATH is set -ifdef USE_SHARED_LIB -RUN_FSVERITY = LD_LIBRARY_PATH=./ $(TEST_WRAPPER_PROG) ./$(FSVERITY) -else -RUN_FSVERITY = $(TEST_WRAPPER_PROG) ./$(FSVERITY) -endif - -############################################################################## - -#### Library - -SOVERSION := 0 -LIB_CFLAGS := $(CFLAGS) -fvisibility=hidden -LIB_SRC := $(wildcard lib/*.c) -ifeq ($(MINGW),1) -LIB_SRC := $(filter-out lib/enable.c,${LIB_SRC}) -endif -LIB_HEADERS := $(wildcard lib/*.h) $(COMMON_HEADERS) -STATIC_LIB_OBJ := $(LIB_SRC:.c=.o) -SHARED_LIB_OBJ := $(LIB_SRC:.c=.shlib.o) - -# Compile static library object files -$(STATIC_LIB_OBJ): %.o: %.c $(LIB_HEADERS) .build-config - $(QUIET_CC) $(CC) -o $@ -c $(CPPFLAGS) $(LIB_CFLAGS) $< - -# Compile shared library object files -$(SHARED_LIB_OBJ): %.shlib.o: %.c $(LIB_HEADERS) .build-config - $(QUIET_CC) $(CC) -o $@ -c $(CPPFLAGS) $(LIB_CFLAGS) -fPIC $< - -# Create static library -libfsverity.a:$(STATIC_LIB_OBJ) - $(QUIET_AR) $(AR) cr $@ $+ - -DEFAULT_TARGETS += libfsverity.a - -# Create shared library -libfsverity.so.$(SOVERSION):$(SHARED_LIB_OBJ) - $(QUIET_CCLD) $(CC) -o $@ -Wl,-soname=$@ -shared $+ \ - $(CFLAGS) $(LDFLAGS) $(LDLIBS) - -DEFAULT_TARGETS += libfsverity.so.$(SOVERSION) - -# Create the symlink libfsverity.so => libfsverity.so.$(SOVERSION) -libfsverity.so:libfsverity.so.$(SOVERSION) - $(QUIET_LN) ln -sf $+ $@ - -DEFAULT_TARGETS += libfsverity.so - -############################################################################## - -#### Programs - -ALL_PROG_SRC := $(wildcard programs/*.c) -ALL_PROG_OBJ := $(ALL_PROG_SRC:.c=.o) -ALL_PROG_HEADERS := $(wildcard programs/*.h) $(COMMON_HEADERS) -PROG_COMMON_SRC := programs/utils.c -PROG_COMMON_OBJ := $(PROG_COMMON_SRC:.c=.o) -FSVERITY_PROG_OBJ := $(PROG_COMMON_OBJ) \ - programs/cmd_digest.o \ - programs/cmd_sign.o \ - programs/fsverity.o -ifneq ($(MINGW),1) -FSVERITY_PROG_OBJ += \ - programs/cmd_enable.o \ - programs/cmd_measure.o -endif -TEST_PROG_SRC := $(wildcard programs/test_*.c) -TEST_PROGRAMS := $(TEST_PROG_SRC:programs/%.c=%$(EXEEXT)) - -# Compile program object files -$(ALL_PROG_OBJ): %.o: %.c $(ALL_PROG_HEADERS) .build-config - $(QUIET_CC) $(CC) -o $@ -c $(CPPFLAGS) $(CFLAGS) $< - -# Link the fsverity program -ifdef USE_SHARED_LIB -$(FSVERITY): $(FSVERITY_PROG_OBJ) libfsverity.so - $(QUIET_CCLD) $(CC) -o $@ $(FSVERITY_PROG_OBJ) \ - $(CFLAGS) $(LDFLAGS) -L. -lfsverity -else -$(FSVERITY): $(FSVERITY_PROG_OBJ) libfsverity.a - $(QUIET_CCLD) $(CC) -o $@ $+ $(CFLAGS) $(LDFLAGS) $(LDLIBS) -endif - -DEFAULT_TARGETS += $(FSVERITY) - -# Link the test programs -$(TEST_PROGRAMS): %$(EXEEXT): programs/%.o $(PROG_COMMON_OBJ) libfsverity.a - $(QUIET_CCLD) $(CC) -o $@ $+ $(CFLAGS) $(LDFLAGS) $(LDLIBS) - -############################################################################## - -SPECIAL_TARGETS := all test_programs check install uninstall help clean - -FORCE: - -.PHONY: $(SPECIAL_TARGETS) FORCE - -.DEFAULT_GOAL = all - -all:$(DEFAULT_TARGETS) - -test_programs:$(TEST_PROGRAMS) - -# This just runs some quick, portable tests. Use scripts/run-tests.sh if you -# want to run the full tests. -check:$(FSVERITY) test_programs - for prog in $(TEST_PROGRAMS); do \ - $(TEST_WRAPPER_PROG) ./$$prog || exit 1; \ - done - $(RUN_FSVERITY) --help > /dev/null - $(RUN_FSVERITY) --version > /dev/null - $(RUN_FSVERITY) sign $(FSVERITY) fsverity.sig \ - --key=testdata/key.pem --cert=testdata/cert.pem > /dev/null - $(RUN_FSVERITY) sign $(FSVERITY) fsverity.sig --hash=sha512 \ - --block-size=512 --salt=12345678 \ - --key=testdata/key.pem --cert=testdata/cert.pem > /dev/null - $(RUN_FSVERITY) digest $(FSVERITY) --hash=sha512 \ - --block-size=512 --salt=12345678 > /dev/null - rm -f fsverity.sig - @echo "All tests passed!" +clean: + rm -f $(EXE) $(OBJ) install:all - install -d $(DESTDIR)$(LIBDIR)/pkgconfig $(DESTDIR)$(INCDIR) $(DESTDIR)$(BINDIR) - install -m755 $(FSVERITY) $(DESTDIR)$(BINDIR) - install -m644 libfsverity.a $(DESTDIR)$(LIBDIR) - install -m755 libfsverity.so.$(SOVERSION) $(DESTDIR)$(LIBDIR) - ln -sf libfsverity.so.$(SOVERSION) $(DESTDIR)$(LIBDIR)/libfsverity.so - install -m644 include/libfsverity.h $(DESTDIR)$(INCDIR) - sed -e "s|@PREFIX@|$(PREFIX)|" \ - -e "s|@LIBDIR@|$(LIBDIR)|" \ - -e "s|@INCDIR@|$(INCDIR)|" \ - lib/libfsverity.pc.in \ - > $(DESTDIR)$(LIBDIR)/pkgconfig/libfsverity.pc - chmod 644 $(DESTDIR)$(LIBDIR)/pkgconfig/libfsverity.pc - -uninstall: - rm -f $(DESTDIR)$(BINDIR)/$(FSVERITY) - rm -f $(DESTDIR)$(LIBDIR)/libfsverity.a - rm -f $(DESTDIR)$(LIBDIR)/libfsverity.so.$(SOVERSION) - rm -f $(DESTDIR)$(LIBDIR)/libfsverity.so - rm -f $(DESTDIR)$(LIBDIR)/pkgconfig/libfsverity.pc - rm -f $(DESTDIR)$(INCDIR)/libfsverity.h + install -Dm755 -t $(DESTDIR)/bin $(EXE) -help: - @echo "Available targets:" - @echo "------------------" - @for target in $(DEFAULT_TARGETS) $(TEST_PROGRAMS) $(SPECIAL_TARGETS); \ - do \ - echo $$target; \ - done - -clean: - rm -f $(DEFAULT_TARGETS) $(TEST_PROGRAMS) \ - lib/*.o programs/*.o .build-config fsverity.sig +.PHONY: all clean install diff --git a/NEWS.md b/NEWS.md deleted file mode 100644 index 8745745..0000000 --- a/NEWS.md +++ /dev/null @@ -1,43 +0,0 @@ -# fsverity-utils release notes - -## Version 1.3 - -* Added a `fsverity digest` subcommand. - -* Added `libfsverity_enable()` and `libfsverity_enable_with_sig()`. - -* Added basic support for Windows builds of `fsverity` using MinGW. - -* `fsverity` now defaults to 4096-byte blocks on all platforms. - -* libfsverity now will use SHA-256 with 4096-byte blocks if the - `hash_algorithm` and `block_size` fields are left 0. - -* `make install` now installs a pkg-config file for libfsverity. - -* The Makefile now uses pkg-config to get the libcrypto build flags. - -* Fixed `make check` with `USE_SHARED_LIB=1`. - -## Version 1.2 - -* Changed license from GPL to MIT. - -* Fixed build error when /bin/sh is dash. - -## Version 1.1 - -* Split the file digest computation and signing functionality of the - `fsverity` program into a library `libfsverity`. See `README.md` - and `Makefile` for more details. - -* Improved the Makefile. - -* Added some tests. They can be run using `make check`. Also added - `scripts/run-tests.sh` which does more extensive prerelease tests. - -* Lots of cleanups and other small improvements. - -## Version 1.0 - -* First official release of fsverity-utils. @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. @@ -1,31 +1,21 @@ -# fsverity-utils +# Introduction -## Introduction - -This is fsverity-utils, a set of userspace utilities for fs-verity. -fs-verity is a Linux kernel feature that does transparent on-demand +This is `fsverity`, a userspace utility for fs-verity. fs-verity is a +Linux kernel feature that does transparent on-demand integrity/authenticity verification of the contents of read-only files, using a hidden Merkle tree (hash tree) associated with the -file. It is similar to dm-verity, but implemented at the file level -rather than at the block device level. See the [kernel -documentation](https://www.kernel.org/doc/html/latest/filesystems/fsverity.html) -for more information about fs-verity. - -fs-verity is supported by the ext4 and f2fs filesystems in Linux v5.4 -and later when configured with `CONFIG_FS_VERITY=y` and when the -`verity` filesystem feature flag has been enabled. Other filesystems -might add support for fs-verity in the future. +file. The mechanism is similar to dm-verity, but implemented at the +file level rather than at the block device level. The `fsverity` +utility allows you to set up fs-verity protected files. -fsverity-utils currently contains just one program, `fsverity`. The -`fsverity` program allows you to set up fs-verity protected files. -In addition, the file digest computation and signing functionality of -`fsverity` is optionally exposed through a C library `libfsverity`. -See `libfsverity.h` for the API of this library. +fs-verity will initially be supported by the ext4 and f2fs +filesystems, but it may later be supported by other filesystems too. -## Building and installing +# Building and installing -fsverity-utils uses the OpenSSL library, so you first must install the -needed development files. For example, on Debian-based systems, run: +The `fsverity` utility uses the OpenSSL library, so you first must +install the needed development files. For example, on Debian-based +systems, run: ```bash sudo apt-get install libssl-dev @@ -33,37 +23,16 @@ needed development files. For example, on Debian-based systems, run: OpenSSL must be version 1.0.0 or later. -Then, to build and install fsverity-utils: +Then, to build and install: ```bash make sudo make install ``` -By default, the following targets are built and installed: the program -`fsverity`, the static library `libfsverity.a`, and the shared library -`libfsverity.so`. You can also run `make check` to build and run the -tests, or `make help` to display all available build targets. - -By default, `fsverity` is statically linked to `libfsverity`. You can -use `make USE_SHARED_LIB=1` to use dynamic linking instead. - -See the `Makefile` for other supported build and installation options. - -### Building on Windows - -There is minimal support for building Windows executables using MinGW. -```bash - make CC=x86_64-w64-mingw32-gcc -``` - -`fsverity.exe` will be built, and it supports the `digest` and `sign` commands. - -A Windows build of OpenSSL/libcrypto needs to be available. - -## Examples +# Examples -### Basic use +## Basic use ```bash mkfs.ext4 -O verity /dev/vdc @@ -72,19 +41,19 @@ A Windows build of OpenSSL/libcrypto needs to be available. # Create a test file head -c 1000000 /dev/urandom > file - sha256sum file + md5sum file # Enable verity on the file fsverity enable file - # Show the verity file digest + # Show the verity file measurement fsverity measure file # File should still be readable as usual. However, all data read # is now transparently checked against a hidden Merkle tree, whose - # root hash is incorporated into the verity file digest. Reads of - # any corrupted parts of the data will fail. - sha256sum file + # root hash is incorporated into the verity file measurement. + # Reads of any corrupted parts of the data will fail. + md5sum file ``` Note that in the above example, the file isn't signed. Therefore, to @@ -92,13 +61,13 @@ get any authenticity protection (as opposed to just integrity protection), the output of `fsverity measure` needs to be compared against a trusted value. -### Using builtin signatures +## Using builtin signatures With `CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y`, the filesystem supports -automatically verifying a signed file digest that has been included in -the verity metadata. The signature is verified against the set of -X.509 certificates that have been loaded into the ".fs-verity" kernel -keyring. Here's an example: +automatically verifying a signed file measurement that has been +included in the verity metadata. The signature is verified against +the set of X.509 certificates that have been loaded into the +".fs-verity" kernel keyring. Here's an example: ```bash # Generate a new certificate and private key: @@ -118,15 +87,11 @@ keyring. Here's an example: sysctl fs.verity.require_signatures=1 # Now set up fs-verity on a test file: - sha256sum file + md5sum file fsverity sign file file.sig --key=key.pem --cert=cert.pem fsverity enable file --signature=file.sig rm -f file.sig - sha256sum file - - # The digest to be signed can also be printed separately, hex - # encoded, in case the integrated signing cannot be used: - fsverity digest file --compact --for-builtin-sig | tr -d '\n' | xxd -p -r | openssl smime -sign -in /dev/stdin ... + md5sum file ``` By default, it's not required that verity files have a signature. @@ -138,28 +103,25 @@ Note: applications generally still need to check whether the file they're accessing really is a verity file, since an attacker could replace a verity file with a regular one. -### With IMA +## With IMA IMA support for fs-verity is planned. -## Notices +# Notices -fsverity-utils is provided under the terms of the MIT license. A copy -of this license can be found in the file named [LICENSE](LICENSE). +This project is provided under the terms of the GNU General Public +License, version 2; or at your option, any later version. A copy of the +GPLv2 can be found in the file named [COPYING](COPYING). -Send questions and bug reports to linux-fscrypt@vger.kernel.org. +Permission to link to OpenSSL (libcrypto) is granted. -Signed release tarballs for fsverity-utils can be found on -[kernel.org](https://kernel.org/pub/linux/kernel/people/ebiggers/fsverity-utils/). +Send questions and bug reports to linux-fscrypt@vger.kernel.org. -## Contributing +# Submitting patches -Send patches to linux-fscrypt@vger.kernel.org with the additional tag -`fsverity-utils` in the subject, i.e. `[fsverity-utils PATCH]`. -Patches should follow the Linux kernel's coding style. A -`.clang-format` file is provided to approximate this coding style; -consider using `git clang-format`. Additionally, like the Linux -kernel itself, patches require the following "sign-off" procedure: +Send patches to linux-fscrypt@vger.kernel.org. Patches should follow +the Linux kernel's coding style. Additionally, like the Linux kernel +itself, patches require the following "sign-off" procedure: The sign-off is a simple line at the end of the explanation for the patch, which certifies that you wrote it or otherwise have the right diff --git a/programs/cmd_enable.c b/cmd_enable.c index 14c3c17..1646299 100644 --- a/programs/cmd_enable.c +++ b/cmd_enable.c @@ -1,19 +1,48 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: GPL-2.0+ /* * The 'fsverity enable' command * - * Copyright 2018 Google LLC + * Copyright (C) 2018 Google LLC * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. + * Written by Eric Biggers. */ -#include "fsverity.h" - #include <fcntl.h> #include <getopt.h> #include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> + +#include "commands.h" +#include "fsverity_uapi.h" +#include "hash_algs.h" + +static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr) +{ + char *end; + unsigned long n = strtoul(arg, &end, 10); + const struct fsverity_hash_alg *alg; + + if (*alg_ptr != 0) { + error_msg("--hash-alg can only be specified once"); + return false; + } + + /* Specified by number? */ + if (n > 0 && n < INT32_MAX && *end == '\0') { + *alg_ptr = n; + return true; + } + + /* Specified by name? */ + alg = find_hash_alg_by_name(arg); + if (alg != NULL) { + *alg_ptr = alg - fsverity_hash_algs; + return true; + } + return false; +} static bool read_signature(const char *filename, u8 **sig_ret, u32 *sig_size_ret) @@ -48,6 +77,13 @@ out: return ok; } +enum { + OPT_HASH_ALG, + OPT_BLOCK_SIZE, + OPT_SALT, + OPT_SIGNATURE, +}; + static const struct option longopts[] = { {"hash-alg", required_argument, NULL, OPT_HASH_ALG}, {"block-size", required_argument, NULL, OPT_BLOCK_SIZE}, @@ -60,9 +96,9 @@ static const struct option longopts[] = { int fsverity_cmd_enable(const struct fsverity_command *cmd, int argc, char *argv[]) { - struct libfsverity_merkle_tree_params tree_params = { .version = 1 }; + struct fsverity_enable_arg arg = { .version = 1 }; + u8 *salt = NULL; u8 *sig = NULL; - u32 sig_size = 0; struct filedes file; int status; int c; @@ -70,18 +106,26 @@ int fsverity_cmd_enable(const struct fsverity_command *cmd, while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) { switch (c) { case OPT_HASH_ALG: + if (!parse_hash_alg_option(optarg, &arg.hash_algorithm)) + goto out_usage; + break; case OPT_BLOCK_SIZE: + if (!parse_block_size_option(optarg, &arg.block_size)) + goto out_usage; + break; case OPT_SALT: - if (!parse_tree_param(c, optarg, &tree_params)) + if (!parse_salt_option(optarg, &salt, &arg.salt_size)) goto out_usage; + arg.salt_ptr = (uintptr_t)salt; break; case OPT_SIGNATURE: if (sig != NULL) { error_msg("--signature can only be specified once"); goto out_usage; } - if (!read_signature(optarg, &sig, &sig_size)) + if (!read_signature(optarg, &sig, &arg.sig_size)) goto out_err; + arg.sig_ptr = (uintptr_t)sig; break; default: goto out_usage; @@ -94,10 +138,15 @@ int fsverity_cmd_enable(const struct fsverity_command *cmd, if (argc != 1) goto out_usage; + if (arg.hash_algorithm == 0) + arg.hash_algorithm = FS_VERITY_HASH_ALG_DEFAULT; + + if (arg.block_size == 0) + arg.block_size = get_default_block_size(); + if (!open_file(&file, argv[0], O_RDONLY, 0)) goto out_err; - - if (libfsverity_enable_with_sig(file.fd, &tree_params, sig, sig_size)) { + if (ioctl(file.fd, FS_IOC_ENABLE_VERITY, &arg) != 0) { error_msg_errno("FS_IOC_ENABLE_VERITY failed on '%s'", file.name); filedes_close(&file); @@ -108,7 +157,7 @@ int fsverity_cmd_enable(const struct fsverity_command *cmd, status = 0; out: - destroy_tree_params(&tree_params); + free(salt); free(sig); return status; diff --git a/programs/cmd_measure.c b/cmd_measure.c index d78969c..574e3ca 100644 --- a/programs/cmd_measure.c +++ b/cmd_measure.c @@ -1,26 +1,28 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: GPL-2.0+ /* * The 'fsverity measure' command * - * Copyright 2018 Google LLC + * Copyright (C) 2018 Google LLC * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. + * Written by Eric Biggers. */ -#include "fsverity.h" - #include <fcntl.h> +#include <stdlib.h> #include <sys/ioctl.h> -/* Display the fs-verity digest of the given verity file(s). */ +#include "commands.h" +#include "fsverity_uapi.h" +#include "hash_algs.h" + +/* Display the measurement of the given verity file(s). */ int fsverity_cmd_measure(const struct fsverity_command *cmd, int argc, char *argv[]) { struct fsverity_digest *d = NULL; struct filedes file; char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1]; + const struct fsverity_hash_alg *hash_alg; char _hash_alg_name[32]; const char *hash_alg_name; int status; @@ -46,8 +48,10 @@ int fsverity_cmd_measure(const struct fsverity_command *cmd, ASSERT(d->digest_size <= FS_VERITY_MAX_DIGEST_SIZE); bin2hex(d->digest, d->digest_size, digest_hex); - hash_alg_name = libfsverity_get_hash_name(d->digest_algorithm); - if (!hash_alg_name) { + hash_alg = find_hash_alg_by_num(d->digest_algorithm); + if (hash_alg) { + hash_alg_name = hash_alg->name; + } else { sprintf(_hash_alg_name, "ALG_%u", d->digest_algorithm); hash_alg_name = _hash_alg_name; } diff --git a/cmd_sign.c b/cmd_sign.c new file mode 100644 index 0000000..dcb37ce --- /dev/null +++ b/cmd_sign.c @@ -0,0 +1,635 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The 'fsverity sign' command + * + * Copyright (C) 2018 Google LLC + * + * Written by Eric Biggers. + */ + +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#include <stdlib.h> +#include <string.h> + +#include "commands.h" +#include "fsverity_uapi.h" +#include "hash_algs.h" + +/* + * Merkle tree properties. The file measurement is the hash of this structure + * excluding the signature and with the sig_size field set to 0. + */ +struct fsverity_descriptor { + __u8 version; /* must be 1 */ + __u8 hash_algorithm; /* Merkle tree hash algorithm */ + __u8 log_blocksize; /* log2 of size of data and tree blocks */ + __u8 salt_size; /* size of salt in bytes; 0 if none */ + __le32 sig_size; /* size of signature in bytes; 0 if none */ + __le64 data_size; /* size of file the Merkle tree is built over */ + __u8 root_hash[64]; /* Merkle tree root hash */ + __u8 salt[32]; /* salt prepended to each hashed block */ + __u8 __reserved[144]; /* must be 0's */ + __u8 signature[]; /* optional PKCS#7 signature */ +}; + +/* + * Format in which verity file measurements are signed. This is the same as + * 'struct fsverity_digest', except here some magic bytes are prepended to + * provide some context about what is being signed in case the same key is used + * for non-fsverity purposes, and here the fields have fixed endianness. + */ +struct fsverity_signed_digest { + char magic[8]; /* must be "FSVerity" */ + __le16 digest_algorithm; + __le16 digest_size; + __u8 digest[]; +}; + +static void __printf(1, 2) __cold +error_msg_openssl(const char *format, ...) +{ + va_list va; + + va_start(va, format); + do_error_msg(format, va, 0); + va_end(va); + + if (ERR_peek_error() == 0) + return; + + fprintf(stderr, "OpenSSL library errors:\n"); + ERR_print_errors_fp(stderr); +} + +/* Read a PEM PKCS#8 formatted private key */ +static EVP_PKEY *read_private_key(const char *keyfile) +{ + BIO *bio; + EVP_PKEY *pkey; + + bio = BIO_new_file(keyfile, "r"); + if (!bio) { + error_msg_openssl("can't open '%s' for reading", keyfile); + return NULL; + } + + pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + if (!pkey) { + error_msg_openssl("Failed to parse private key file '%s'.\n" + " Note: it must be in PEM PKCS#8 format.", + keyfile); + } + BIO_free(bio); + return pkey; +} + +/* Read a PEM X.509 formatted certificate */ +static X509 *read_certificate(const char *certfile) +{ + BIO *bio; + X509 *cert; + + bio = BIO_new_file(certfile, "r"); + if (!bio) { + error_msg_openssl("can't open '%s' for reading", certfile); + return NULL; + } + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + if (!cert) { + error_msg_openssl("Failed to parse X.509 certificate file '%s'.\n" + " Note: it must be in PEM format.", + certfile); + } + BIO_free(bio); + return cert; +} + +#ifdef OPENSSL_IS_BORINGSSL + +static bool sign_pkcs7(const void *data_to_sign, size_t data_size, + EVP_PKEY *pkey, X509 *cert, const EVP_MD *md, + u8 **sig_ret, u32 *sig_size_ret) +{ + CBB out, outer_seq, wrapped_seq, seq, digest_algos_set, digest_algo, + null, content_info, issuer_and_serial, signer_infos, + signer_info, sign_algo, signature; + EVP_MD_CTX md_ctx; + u8 *name_der = NULL, *sig = NULL, *pkcs7_data = NULL; + size_t pkcs7_data_len, sig_len; + int name_der_len, sig_nid; + bool ok = false; + + EVP_MD_CTX_init(&md_ctx); + BIGNUM *serial = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), NULL); + + if (!CBB_init(&out, 1024)) { + error_msg("out of memory"); + goto out; + } + + name_der_len = i2d_X509_NAME(X509_get_subject_name(cert), &name_der); + if (name_der_len < 0) { + error_msg_openssl("i2d_X509_NAME failed"); + goto out; + } + + if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey)) { + error_msg_openssl("EVP_DigestSignInit failed"); + goto out; + } + + sig_len = EVP_PKEY_size(pkey); + sig = xmalloc(sig_len); + if (!EVP_DigestSign(&md_ctx, sig, &sig_len, data_to_sign, data_size)) { + error_msg_openssl("EVP_DigestSign failed"); + goto out; + } + + sig_nid = EVP_PKEY_id(pkey); + /* To mirror OpenSSL behaviour, always use |NID_rsaEncryption| with RSA + * rather than the combined hash+pkey NID. */ + if (sig_nid != NID_rsaEncryption) { + OBJ_find_sigid_by_algs(&sig_nid, EVP_MD_type(md), + EVP_PKEY_id(pkey)); + } + + // See https://tools.ietf.org/html/rfc2315#section-7 + if (!CBB_add_asn1(&out, &outer_seq, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) || + !CBB_add_asn1(&outer_seq, &wrapped_seq, CBS_ASN1_CONTEXT_SPECIFIC | + CBS_ASN1_CONSTRUCTED | 0) || + // See https://tools.ietf.org/html/rfc2315#section-9.1 + !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&seq, 1 /* version */) || + !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) || + !CBB_add_asn1(&digest_algos_set, &digest_algo, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) || + !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) || + !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&content_info, NID_pkcs7_data) || + !CBB_add_asn1(&seq, &signer_infos, CBS_ASN1_SET) || + !CBB_add_asn1(&signer_infos, &signer_info, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&signer_info, 1 /* version */) || + !CBB_add_asn1(&signer_info, &issuer_and_serial, + CBS_ASN1_SEQUENCE) || + !CBB_add_bytes(&issuer_and_serial, name_der, name_der_len) || + !BN_marshal_asn1(&issuer_and_serial, serial) || + !CBB_add_asn1(&signer_info, &digest_algo, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) || + !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) || + !CBB_add_asn1(&signer_info, &sign_algo, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&sign_algo, sig_nid) || + !CBB_add_asn1(&sign_algo, &null, CBS_ASN1_NULL) || + !CBB_add_asn1(&signer_info, &signature, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&signature, sig, sig_len) || + !CBB_finish(&out, &pkcs7_data, &pkcs7_data_len)) { + error_msg_openssl("failed to construct PKCS#7 data"); + goto out; + } + + *sig_ret = xmemdup(pkcs7_data, pkcs7_data_len); + *sig_size_ret = pkcs7_data_len; + ok = true; +out: + BN_free(serial); + EVP_MD_CTX_cleanup(&md_ctx); + CBB_cleanup(&out); + free(sig); + OPENSSL_free(name_der); + OPENSSL_free(pkcs7_data); + return ok; +} + +#else /* OPENSSL_IS_BORINGSSL */ + +static BIO *new_mem_buf(const void *buf, size_t size) +{ + BIO *bio; + + ASSERT(size <= INT_MAX); + /* + * Prior to OpenSSL 1.1.0, BIO_new_mem_buf() took a non-const pointer, + * despite still marking the resulting bio as read-only. So cast away + * the const to avoid a compiler warning with older OpenSSL versions. + */ + bio = BIO_new_mem_buf((void *)buf, size); + if (!bio) + error_msg_openssl("out of memory"); + return bio; +} + +static bool sign_pkcs7(const void *data_to_sign, size_t data_size, + EVP_PKEY *pkey, X509 *cert, const EVP_MD *md, + u8 **sig_ret, u32 *sig_size_ret) +{ + /* + * PKCS#7 signing flags: + * + * - PKCS7_BINARY signing binary data, so skip MIME translation + * + * - PKCS7_DETACHED omit the signed data (include signature only) + * + * - PKCS7_NOATTR omit extra authenticated attributes, such as + * SMIMECapabilities + * + * - PKCS7_NOCERTS omit the signer's certificate + * + * - PKCS7_PARTIAL PKCS7_sign() creates a handle only, then + * PKCS7_sign_add_signer() can add a signer later. + * This is necessary to change the message digest + * algorithm from the default of SHA-1. Requires + * OpenSSL 1.0.0 or later. + */ + int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR | + PKCS7_NOCERTS | PKCS7_PARTIAL; + u8 *sig; + u32 sig_size; + BIO *bio = NULL; + PKCS7 *p7 = NULL; + bool ok = false; + + bio = new_mem_buf(data_to_sign, data_size); + if (!bio) + goto out; + + p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags); + if (!p7) { + error_msg_openssl("failed to initialize PKCS#7 signature object"); + goto out; + } + + if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) { + error_msg_openssl("failed to add signer to PKCS#7 signature object"); + goto out; + } + + if (PKCS7_final(p7, bio, pkcs7_flags) != 1) { + error_msg_openssl("failed to finalize PKCS#7 signature"); + goto out; + } + + BIO_free(bio); + bio = BIO_new(BIO_s_mem()); + if (!bio) { + error_msg_openssl("out of memory"); + goto out; + } + + if (i2d_PKCS7_bio(bio, p7) != 1) { + error_msg_openssl("failed to DER-encode PKCS#7 signature object"); + goto out; + } + + sig_size = BIO_get_mem_data(bio, &sig); + *sig_ret = xmemdup(sig, sig_size); + *sig_size_ret = sig_size; + ok = true; +out: + PKCS7_free(p7); + BIO_free(bio); + return ok; +} + +#endif /* !OPENSSL_IS_BORINGSSL */ + +/* + * Sign the specified @data_to_sign of length @data_size bytes using the private + * key in @keyfile, the certificate in @certfile, and the hash algorithm + * @hash_alg. Returns the DER-formatted PKCS#7 signature in @sig_ret and + * @sig_size_ret. + */ +static bool sign_data(const void *data_to_sign, size_t data_size, + const char *keyfile, const char *certfile, + const struct fsverity_hash_alg *hash_alg, + u8 **sig_ret, u32 *sig_size_ret) +{ + EVP_PKEY *pkey = NULL; + X509 *cert = NULL; + const EVP_MD *md; + bool ok = false; + + pkey = read_private_key(keyfile); + if (!pkey) + goto out; + + cert = read_certificate(certfile); + if (!cert) + goto out; + + OpenSSL_add_all_digests(); + md = EVP_get_digestbyname(hash_alg->name); + if (!md) { + fprintf(stderr, + "Warning: '%s' algorithm not found in OpenSSL library.\n" + " Falling back to SHA-256 signature.\n", + hash_alg->name); + md = EVP_sha256(); + } + + ok = sign_pkcs7(data_to_sign, data_size, pkey, cert, md, + sig_ret, sig_size_ret); +out: + EVP_PKEY_free(pkey); + X509_free(cert); + return ok; +} + +static bool write_signature(const char *filename, const u8 *sig, u32 sig_size) +{ + struct filedes file; + bool ok; + + if (!open_file(&file, filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) + return false; + ok = full_write(&file, sig, sig_size); + ok &= filedes_close(&file); + return ok; +} + +#define FS_VERITY_MAX_LEVELS 64 + +struct block_buffer { + u32 filled; + u8 *data; +}; + +/* + * Hash a block, writing the result to the next level's pending block buffer. + * Returns true if the next level's block became full, else false. + */ +static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur, + u32 block_size, const u8 *salt, u32 salt_size) +{ + struct block_buffer *next = cur + 1; + + /* Zero-pad the block if it's shorter than block_size. */ + memset(&cur->data[cur->filled], 0, block_size - cur->filled); + + hash_init(hash); + hash_update(hash, salt, salt_size); + hash_update(hash, cur->data, block_size); + hash_final(hash, &next->data[next->filled]); + + next->filled += hash->alg->digest_size; + cur->filled = 0; + + return next->filled + hash->alg->digest_size > block_size; +} + +/* + * Compute the file's Merkle tree root hash using the given hash algorithm, + * block size, and salt. + */ +static bool compute_root_hash(struct filedes *file, u64 file_size, + struct hash_ctx *hash, u32 block_size, + const u8 *salt, u32 salt_size, u8 *root_hash) +{ + const u32 hashes_per_block = block_size / hash->alg->digest_size; + const u32 padded_salt_size = roundup(salt_size, hash->alg->block_size); + u8 *padded_salt = xzalloc(padded_salt_size); + u64 blocks; + int num_levels = 0; + int level; + struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {}; + struct block_buffer *buffers = &_buffers[1]; + u64 offset; + bool ok = false; + + if (salt_size != 0) + memcpy(padded_salt, salt, salt_size); + + /* Compute number of levels */ + for (blocks = DIV_ROUND_UP(file_size, block_size); blocks > 1; + blocks = DIV_ROUND_UP(blocks, hashes_per_block)) { + ASSERT(num_levels < FS_VERITY_MAX_LEVELS); + num_levels++; + } + + /* + * Allocate the block buffers. Buffer "-1" is for data blocks. + * Buffers 0 <= level < num_levels are for the actual tree levels. + * Buffer 'num_levels' is for the root hash. + */ + for (level = -1; level < num_levels; level++) + buffers[level].data = xmalloc(block_size); + buffers[num_levels].data = root_hash; + + /* Hash each data block, also hashing the tree blocks as they fill up */ + for (offset = 0; offset < file_size; offset += block_size) { + buffers[-1].filled = min(block_size, file_size - offset); + + if (!full_read(file, buffers[-1].data, buffers[-1].filled)) + goto out; + + level = -1; + while (hash_one_block(hash, &buffers[level], block_size, + padded_salt, padded_salt_size)) { + level++; + ASSERT(level < num_levels); + } + } + /* Finish all nonempty pending tree blocks */ + for (level = 0; level < num_levels; level++) { + if (buffers[level].filled != 0) + hash_one_block(hash, &buffers[level], block_size, + padded_salt, padded_salt_size); + } + + /* Root hash was filled by the last call to hash_one_block() */ + ASSERT(buffers[num_levels].filled == hash->alg->digest_size); + ok = true; +out: + for (level = -1; level < num_levels; level++) + free(buffers[level].data); + free(padded_salt); + return ok; +} + +/* + * Compute the fs-verity measurement of the given file. + * + * The fs-verity measurement is the hash of the fsverity_descriptor, which + * contains the Merkle tree properties including the root hash. + */ +static bool compute_file_measurement(const char *filename, + const struct fsverity_hash_alg *hash_alg, + u32 block_size, const u8 *salt, + u32 salt_size, u8 *measurement) +{ + struct filedes file = { .fd = -1 }; + struct hash_ctx *hash = hash_create(hash_alg); + u64 file_size; + struct fsverity_descriptor desc; + bool ok = false; + + if (!open_file(&file, filename, O_RDONLY, 0)) + goto out; + + if (!get_file_size(&file, &file_size)) + goto out; + + memset(&desc, 0, sizeof(desc)); + desc.version = 1; + desc.hash_algorithm = hash_alg - fsverity_hash_algs; + + ASSERT(is_power_of_2(block_size)); + desc.log_blocksize = ilog2(block_size); + + if (salt_size != 0) { + if (salt_size > sizeof(desc.salt)) { + error_msg("Salt too long (got %u bytes; max is %zu bytes)", + salt_size, sizeof(desc.salt)); + goto out; + } + memcpy(desc.salt, salt, salt_size); + desc.salt_size = salt_size; + } + + desc.data_size = cpu_to_le64(file_size); + + /* Root hash of empty file is all 0's */ + if (file_size != 0 && + !compute_root_hash(&file, file_size, hash, block_size, salt, + salt_size, desc.root_hash)) + goto out; + + hash_full(hash, &desc, sizeof(desc), measurement); + ok = true; +out: + filedes_close(&file); + hash_free(hash); + return ok; +} + +enum { + OPT_HASH_ALG, + OPT_BLOCK_SIZE, + OPT_SALT, + OPT_KEY, + OPT_CERT, +}; + +static const struct option longopts[] = { + {"hash-alg", required_argument, NULL, OPT_HASH_ALG}, + {"block-size", required_argument, NULL, OPT_BLOCK_SIZE}, + {"salt", required_argument, NULL, OPT_SALT}, + {"key", required_argument, NULL, OPT_KEY}, + {"cert", required_argument, NULL, OPT_CERT}, + {NULL, 0, NULL, 0} +}; + +/* Sign a file for fs-verity by computing its measurement, then signing it. */ +int fsverity_cmd_sign(const struct fsverity_command *cmd, + int argc, char *argv[]) +{ + const struct fsverity_hash_alg *hash_alg = NULL; + u32 block_size = 0; + u8 *salt = NULL; + u32 salt_size = 0; + const char *keyfile = NULL; + const char *certfile = NULL; + struct fsverity_signed_digest *digest = NULL; + char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1]; + u8 *sig = NULL; + u32 sig_size; + int status; + int c; + + while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) { + switch (c) { + case OPT_HASH_ALG: + if (hash_alg != NULL) { + error_msg("--hash-alg can only be specified once"); + goto out_usage; + } + hash_alg = find_hash_alg_by_name(optarg); + if (hash_alg == NULL) + goto out_usage; + break; + case OPT_BLOCK_SIZE: + if (!parse_block_size_option(optarg, &block_size)) + goto out_usage; + break; + case OPT_SALT: + if (!parse_salt_option(optarg, &salt, &salt_size)) + goto out_usage; + break; + case OPT_KEY: + if (keyfile != NULL) { + error_msg("--key can only be specified once"); + goto out_usage; + } + keyfile = optarg; + break; + case OPT_CERT: + if (certfile != NULL) { + error_msg("--cert can only be specified once"); + goto out_usage; + } + certfile = optarg; + break; + default: + goto out_usage; + } + } + + argv += optind; + argc -= optind; + + if (argc != 2) + goto out_usage; + + if (hash_alg == NULL) + hash_alg = &fsverity_hash_algs[FS_VERITY_HASH_ALG_DEFAULT]; + + if (block_size == 0) + block_size = get_default_block_size(); + + if (keyfile == NULL) { + error_msg("Missing --key argument"); + goto out_usage; + } + if (certfile == NULL) + certfile = keyfile; + + digest = xzalloc(sizeof(*digest) + hash_alg->digest_size); + memcpy(digest->magic, "FSVerity", 8); + digest->digest_algorithm = cpu_to_le16(hash_alg - fsverity_hash_algs); + digest->digest_size = cpu_to_le16(hash_alg->digest_size); + + if (!compute_file_measurement(argv[0], hash_alg, block_size, + salt, salt_size, digest->digest)) + goto out_err; + + if (!sign_data(digest, sizeof(*digest) + hash_alg->digest_size, + keyfile, certfile, hash_alg, &sig, &sig_size)) + goto out_err; + + if (!write_signature(argv[1], sig, sig_size)) + goto out_err; + + bin2hex(digest->digest, hash_alg->digest_size, digest_hex); + printf("Signed file '%s' (%s:%s)\n", argv[0], hash_alg->name, + digest_hex); + status = 0; +out: + free(salt); + free(digest); + free(sig); + return status; + +out_err: + status = 1; + goto out; + +out_usage: + usage(cmd, stderr); + status = 2; + goto out; +} diff --git a/commands.h b/commands.h new file mode 100644 index 0000000..98f9745 --- /dev/null +++ b/commands.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#ifndef COMMANDS_H +#define COMMANDS_H + +#include <stdio.h> + +#include "util.h" + +struct fsverity_command; + +void usage(const struct fsverity_command *cmd, FILE *fp); + +int fsverity_cmd_enable(const struct fsverity_command *cmd, + int argc, char *argv[]); +int fsverity_cmd_measure(const struct fsverity_command *cmd, + int argc, char *argv[]); +int fsverity_cmd_sign(const struct fsverity_command *cmd, + int argc, char *argv[]); + +bool parse_block_size_option(const char *arg, u32 *size_ptr); +u32 get_default_block_size(void); +bool parse_salt_option(const char *arg, u8 **salt_ptr, u32 *salt_size_ptr); + +#endif /* COMMANDS_H */ diff --git a/common/fsverity_uapi.h b/common/fsverity_uapi.h deleted file mode 100644 index a739c9a..0000000 --- a/common/fsverity_uapi.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * fs-verity user API - * - * These ioctls can be used on filesystems that support fs-verity. See the - * "User API" section of Documentation/filesystems/fsverity.rst. - * - * Copyright 2019 Google LLC - */ -#ifndef _UAPI_LINUX_FSVERITY_H -#define _UAPI_LINUX_FSVERITY_H - -#ifndef _WIN32 -#include <linux/ioctl.h> -#include <linux/types.h> -#endif /* !_WIN32 */ - -#define FS_VERITY_HASH_ALG_SHA256 1 -#define FS_VERITY_HASH_ALG_SHA512 2 - -struct fsverity_enable_arg { - __u32 version; - __u32 hash_algorithm; - __u32 block_size; - __u32 salt_size; - __u64 salt_ptr; - __u32 sig_size; - __u32 __reserved1; - __u64 sig_ptr; - __u64 __reserved2[11]; -}; - -struct fsverity_digest { - __u16 digest_algorithm; - __u16 digest_size; /* input/output */ - __u8 digest[]; -}; - -/* - * Struct containing a file's Merkle tree properties. The fs-verity file digest - * is the hash of this struct. A userspace program needs this struct only if it - * needs to compute fs-verity file digests itself, e.g. in order to sign files. - * It isn't needed just to enable fs-verity on a file. - * - * Note: when computing the file digest, 'sig_size' and 'signature' must be left - * zero and empty, respectively. These fields are present only because some - * filesystems reuse this struct as part of their on-disk format. - */ -struct fsverity_descriptor { - __u8 version; /* must be 1 */ - __u8 hash_algorithm; /* Merkle tree hash algorithm */ - __u8 log_blocksize; /* log2 of size of data and tree blocks */ - __u8 salt_size; /* size of salt in bytes; 0 if none */ -#ifdef __KERNEL__ - __le32 sig_size; -#else - __le32 __reserved_0x04; /* must be 0 */ -#endif - __le64 data_size; /* size of file the Merkle tree is built over */ - __u8 root_hash[64]; /* Merkle tree root hash */ - __u8 salt[32]; /* salt prepended to each hashed block */ - __u8 __reserved[144]; /* must be 0's */ -#ifdef __KERNEL__ - __u8 signature[]; -#endif -}; - -/* - * Format in which fs-verity file digests are signed in built-in signatures. - * This is the same as 'struct fsverity_digest', except here some magic bytes - * are prepended to provide some context about what is being signed in case the - * same key is used for non-fsverity purposes, and here the fields have fixed - * endianness. - * - * This struct is specific to the built-in signature verification support, which - * is optional. fs-verity users may also verify signatures in userspace, in - * which case userspace is responsible for deciding on what bytes are signed. - * This struct may still be used, but it doesn't have to be. For example, - * userspace could instead use a string like "sha256:$digest_as_hex_string". - */ -struct fsverity_formatted_digest { - char magic[8]; /* must be "FSVerity" */ - __le16 digest_algorithm; - __le16 digest_size; - __u8 digest[]; -}; - -#define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg) -#define FS_IOC_MEASURE_VERITY _IOWR('f', 134, struct fsverity_digest) - -#endif /* _UAPI_LINUX_FSVERITY_H */ diff --git a/common/win32_defs.h b/common/win32_defs.h deleted file mode 100644 index 29ef9b2..0000000 --- a/common/win32_defs.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * WIN32 compat definitions for libfsverity and the 'fsverity' program - * - * Copyright 2020 Microsoft - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ -#ifndef COMMON_WIN32_DEFS_H -#define COMMON_WIN32_DEFS_H - -/* Some minimal definitions to allow the digest/sign commands to run under Windows */ - -/* All file reads we do need this flag on _WIN32 */ -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -#ifdef _WIN32 - -#include <stdint.h> -#include <inttypes.h> - -#ifndef ENOPKG -# define ENOPKG 65 -#endif - -#ifndef __cold -# define __cold -#endif - -/* For %zu in printf() */ -#ifndef __printf -# define __printf(fmt_idx, vargs_idx) \ - __attribute__((format(gnu_printf, fmt_idx, vargs_idx))) -#endif - -typedef __signed__ char __s8; -typedef unsigned char __u8; -typedef __signed__ short __s16; -typedef unsigned short __u16; -typedef __signed__ int __s32; -typedef unsigned int __u32; -typedef __signed__ long long __s64; -typedef unsigned long long __u64; -typedef __u16 __le16; -typedef __u16 __be16; -typedef __u32 __le32; -typedef __u32 __be32; -typedef __u64 __le64; -typedef __u64 __be64; - -#endif /* _WIN32 */ - -#endif /* COMMON_WIN32_DEFS_H */ diff --git a/programs/fsverity.c b/fsverity.c index b911b2e..6fabfa4 100644 --- a/programs/fsverity.c +++ b/fsverity.c @@ -1,17 +1,19 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: GPL-2.0+ /* * fs-verity userspace tool * - * Copyright 2018 Google LLC + * Copyright (C) 2018 Google LLC * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. + * Written by Eric Biggers. */ -#include "fsverity.h" - #include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "commands.h" +#include "hash_algs.h" static const struct fsverity_command { const char *name; @@ -20,16 +22,6 @@ static const struct fsverity_command { const char *usage_str; } fsverity_commands[] = { { - .name = "digest", - .func = fsverity_cmd_digest, - .short_desc = -"Compute the fs-verity digest of the given file(s), for offline signing", - .usage_str = -" fsverity digest FILE...\n" -" [--hash-alg=HASH_ALG] [--block-size=BLOCK_SIZE] [--salt=SALT]\n" -" [--compact] [--for-builtin-sig]\n" -#ifndef _WIN32 - }, { .name = "enable", .func = fsverity_cmd_enable, .short_desc = "Enable fs-verity on a file", @@ -41,10 +33,9 @@ static const struct fsverity_command { .name = "measure", .func = fsverity_cmd_measure, .short_desc = -"Display the fs-verity digest of the given verity file(s)", +"Display the measurement of the given verity file(s)", .usage_str = " fsverity measure FILE...\n" -#endif /* !_WIN32 */ }, { .name = "sign", .func = fsverity_cmd_sign, @@ -56,17 +47,6 @@ static const struct fsverity_command { } }; -static void show_all_hash_algs(FILE *fp) -{ - u32 alg_num = 1; - const char *name; - - fprintf(fp, "Available hash algorithms:"); - while ((name = libfsverity_get_hash_name(alg_num++)) != NULL) - fprintf(fp, " %s", name); - putc('\n', fp); -} - static void usage_all(FILE *fp) { int i; @@ -79,8 +59,10 @@ static void usage_all(FILE *fp) " Standard options:\n" " fsverity --help\n" " fsverity --version\n" -"\n", fp); +"\n" +"Available hash algorithms: ", fp); show_all_hash_algs(fp); + fputs("\nSee `man fsverity` for more details.\n", fp); } static void usage_cmd(const struct fsverity_command *cmd, FILE *fp) @@ -96,10 +78,20 @@ void usage(const struct fsverity_command *cmd, FILE *fp) usage_all(fp); } +#define PACKAGE_VERSION "v0.0-alpha" +#define PACKAGE_BUGREPORT "linux-fscrypt@vger.kernel.org" + static void show_version(void) { - printf("fsverity v%d.%d\n", FSVERITY_UTILS_MAJOR_VERSION, - FSVERITY_UTILS_MINOR_VERSION); + static const char * const str = +"fsverity " PACKAGE_VERSION "\n" +"Copyright (C) 2018 Google LLC\n" +"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n" +"This is free software: you are free to change and redistribute it.\n" +"There is NO WARRANTY, to the extent permitted by law.\n" +"\n" +"Report bugs to " PACKAGE_BUGREPORT ".\n"; + fputs(str, stdout); } static void handle_common_options(int argc, char *argv[], @@ -135,32 +127,7 @@ static const struct fsverity_command *find_command(const char *name) return NULL; } -static bool parse_hash_alg_option(const char *arg, u32 *alg_ptr) -{ - char *end; - unsigned long n = strtoul(arg, &end, 10); - - if (*alg_ptr != 0) { - error_msg("--hash-alg can only be specified once"); - return false; - } - - /* Specified by number? */ - if (n > 0 && n < INT32_MAX && *end == '\0') { - *alg_ptr = n; - return true; - } - - /* Specified by name? */ - *alg_ptr = libfsverity_find_hash_alg_by_name(arg); - if (*alg_ptr) - return true; - error_msg("unknown hash algorithm: '%s'", arg); - show_all_hash_algs(stderr); - return false; -} - -static bool parse_block_size_option(const char *arg, u32 *size_ptr) +bool parse_block_size_option(const char *arg, u32 *size_ptr) { char *end; unsigned long n = strtoul(arg, &end, 10); @@ -178,8 +145,7 @@ static bool parse_block_size_option(const char *arg, u32 *size_ptr) return true; } -static bool parse_salt_option(const char *arg, u8 **salt_ptr, - u32 *salt_size_ptr) +bool parse_salt_option(const char *arg, u8 **salt_ptr, u32 *salt_size_ptr) { if (*salt_ptr != NULL) { error_msg("--salt can only be specified once"); @@ -194,34 +160,23 @@ static bool parse_salt_option(const char *arg, u8 **salt_ptr, return true; } -bool parse_tree_param(int opt_char, const char *arg, - struct libfsverity_merkle_tree_params *params) +u32 get_default_block_size(void) { - switch (opt_char) { - case OPT_HASH_ALG: - return parse_hash_alg_option(arg, ¶ms->hash_algorithm); - case OPT_BLOCK_SIZE: - return parse_block_size_option(arg, ¶ms->block_size); - case OPT_SALT: - return parse_salt_option(arg, (u8 **)¶ms->salt, - ¶ms->salt_size); - default: - ASSERT(0); - } -} + long n = sysconf(_SC_PAGESIZE); -void destroy_tree_params(struct libfsverity_merkle_tree_params *params) -{ - free((u8 *)params->salt); - memset(params, 0, sizeof(*params)); + if (n <= 0 || n >= INT_MAX || !is_power_of_2(n)) { + fprintf(stderr, + "Warning: invalid _SC_PAGESIZE (%ld). Assuming 4K blocks.\n", + n); + return 4096; + } + return n; } int main(int argc, char *argv[]) { const struct fsverity_command *cmd; - install_libfsverity_error_handler(); - if (argc < 2) { error_msg("no command specified"); usage_all(stderr); diff --git a/fsverity_uapi.h b/fsverity_uapi.h new file mode 100644 index 0000000..da0daf6 --- /dev/null +++ b/fsverity_uapi.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * fs-verity user API + * + * These ioctls can be used on filesystems that support fs-verity. See the + * "User API" section of Documentation/filesystems/fsverity.rst. + * + * Copyright 2019 Google LLC + */ +#ifndef _UAPI_LINUX_FSVERITY_H +#define _UAPI_LINUX_FSVERITY_H + +#include <linux/ioctl.h> +#include <linux/types.h> + +#define FS_VERITY_HASH_ALG_SHA256 1 +#define FS_VERITY_HASH_ALG_SHA512 2 + +struct fsverity_enable_arg { + __u32 version; + __u32 hash_algorithm; + __u32 block_size; + __u32 salt_size; + __u64 salt_ptr; + __u32 sig_size; + __u32 __reserved1; + __u64 sig_ptr; + __u64 __reserved2[11]; +}; + +struct fsverity_digest { + __u16 digest_algorithm; + __u16 digest_size; /* input/output */ + __u8 digest[]; +}; + +#define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg) +#define FS_IOC_MEASURE_VERITY _IOWR('f', 134, struct fsverity_digest) + +#endif /* _UAPI_LINUX_FSVERITY_H */ diff --git a/lib/hash_algs.c b/hash_algs.c index 510ca3e..7251bf2 100644 --- a/lib/hash_algs.c +++ b/hash_algs.c @@ -1,20 +1,19 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: GPL-2.0+ /* * fs-verity hash algorithms * - * Copyright 2018 Google LLC + * Copyright (C) 2018 Google LLC * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. + * Written by Eric Biggers. */ -#include "lib_private.h" - #include <openssl/evp.h> #include <stdlib.h> #include <string.h> +#include "fsverity_uapi.h" +#include "hash_algs.h" + /* ========== libcrypto (OpenSSL) wrappers ========== */ struct openssl_hash_ctx { @@ -26,29 +25,29 @@ struct openssl_hash_ctx { static void openssl_digest_init(struct hash_ctx *_ctx) { struct openssl_hash_ctx *ctx = (void *)_ctx; - int ret; - ret = EVP_DigestInit_ex(ctx->md_ctx, ctx->md, NULL); - BUG_ON(ret != 1); + if (EVP_DigestInit_ex(ctx->md_ctx, ctx->md, NULL) != 1) + fatal_error("EVP_DigestInit_ex() failed for algorithm '%s'", + ctx->base.alg->name); } static void openssl_digest_update(struct hash_ctx *_ctx, const void *data, size_t size) { struct openssl_hash_ctx *ctx = (void *)_ctx; - int ret; - ret = EVP_DigestUpdate(ctx->md_ctx, data, size); - BUG_ON(ret != 1); + if (EVP_DigestUpdate(ctx->md_ctx, data, size) != 1) + fatal_error("EVP_DigestUpdate() failed for algorithm '%s'", + ctx->base.alg->name); } static void openssl_digest_final(struct hash_ctx *_ctx, u8 *digest) { struct openssl_hash_ctx *ctx = (void *)_ctx; - int ret; - ret = EVP_DigestFinal_ex(ctx->md_ctx, digest, NULL); - BUG_ON(ret != 1); + if (EVP_DigestFinal_ex(ctx->md_ctx, digest, NULL) != 1) + fatal_error("EVP_DigestFinal_ex() failed for algorithm '%s'", + ctx->base.alg->name); } static void openssl_digest_ctx_free(struct hash_ctx *_ctx) @@ -69,10 +68,7 @@ openssl_digest_ctx_create(const struct fsverity_hash_alg *alg, const EVP_MD *md) { struct openssl_hash_ctx *ctx; - ctx = libfsverity_zalloc(sizeof(*ctx)); - if (!ctx) - return NULL; - + ctx = xzalloc(sizeof(*ctx)); ctx->base.alg = alg; ctx->base.init = openssl_digest_init; ctx->base.update = openssl_digest_update; @@ -84,22 +80,13 @@ openssl_digest_ctx_create(const struct fsverity_hash_alg *alg, const EVP_MD *md) * with older OpenSSL versions. */ ctx->md_ctx = EVP_MD_CTX_create(); - if (!ctx->md_ctx) { - libfsverity_error_msg("failed to allocate EVP_MD_CTX"); - goto err1; - } + if (!ctx->md_ctx) + fatal_error("out of memory"); ctx->md = md; - if (WARN_ON(EVP_MD_size(md) != alg->digest_size)) - goto err2; + ASSERT(EVP_MD_size(md) == alg->digest_size); return &ctx->base; - -err2: - EVP_MD_CTX_destroy(ctx->md_ctx); -err1: - free(ctx); - return NULL; } static struct hash_ctx *create_sha256_ctx(const struct fsverity_hash_alg *alg) @@ -112,42 +99,9 @@ static struct hash_ctx *create_sha512_ctx(const struct fsverity_hash_alg *alg) return openssl_digest_ctx_create(alg, EVP_sha512()); } -/* ========== Hash utilities ========== */ - -void libfsverity_hash_init(struct hash_ctx *ctx) -{ - ctx->init(ctx); -} - -void libfsverity_hash_update(struct hash_ctx *ctx, const void *data, - size_t size) -{ - ctx->update(ctx, data, size); -} - -void libfsverity_hash_final(struct hash_ctx *ctx, u8 *digest) -{ - ctx->final(ctx, digest); -} - -/* ->init(), ->update(), and ->final() all in one step */ -void libfsverity_hash_full(struct hash_ctx *ctx, const void *data, size_t size, - u8 *digest) -{ - libfsverity_hash_init(ctx); - libfsverity_hash_update(ctx, data, size); - libfsverity_hash_final(ctx, digest); -} - -void libfsverity_free_hash_ctx(struct hash_ctx *ctx) -{ - if (ctx) - ctx->free(ctx); -} - /* ========== Hash algorithm definitions ========== */ -static const struct fsverity_hash_alg fsverity_hash_algs[] = { +const struct fsverity_hash_alg fsverity_hash_algs[] = { [FS_VERITY_HASH_ALG_SHA256] = { .name = "sha256", .digest_size = 32, @@ -162,45 +116,48 @@ static const struct fsverity_hash_alg fsverity_hash_algs[] = { }, }; -LIBEXPORT u32 -libfsverity_find_hash_alg_by_name(const char *name) +const struct fsverity_hash_alg *find_hash_alg_by_name(const char *name) { int i; - if (!name) - return 0; - - for (i = 1; i < ARRAY_SIZE(fsverity_hash_algs); i++) { + for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) { if (fsverity_hash_algs[i].name && !strcmp(name, fsverity_hash_algs[i].name)) - return i; + return &fsverity_hash_algs[i]; } - return 0; + error_msg("unknown hash algorithm: '%s'", name); + fputs("Available hash algorithms: ", stderr); + show_all_hash_algs(stderr); + putc('\n', stderr); + return NULL; } -const struct fsverity_hash_alg *libfsverity_find_hash_alg_by_num(u32 alg_num) +const struct fsverity_hash_alg *find_hash_alg_by_num(unsigned int num) { - if (alg_num < ARRAY_SIZE(fsverity_hash_algs) && - fsverity_hash_algs[alg_num].name) - return &fsverity_hash_algs[alg_num]; + if (num < ARRAY_SIZE(fsverity_hash_algs) && + fsverity_hash_algs[num].name) + return &fsverity_hash_algs[num]; return NULL; } -LIBEXPORT int -libfsverity_get_digest_size(u32 alg_num) +void show_all_hash_algs(FILE *fp) { - const struct fsverity_hash_alg *alg = - libfsverity_find_hash_alg_by_num(alg_num); + int i; + const char *sep = ""; - return alg ? alg->digest_size : -1; + for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) { + if (fsverity_hash_algs[i].name) { + fprintf(fp, "%s%s", sep, fsverity_hash_algs[i].name); + sep = ", "; + } + } } -LIBEXPORT const char * -libfsverity_get_hash_name(u32 alg_num) +/* ->init(), ->update(), and ->final() all in one step */ +void hash_full(struct hash_ctx *ctx, const void *data, size_t size, u8 *digest) { - const struct fsverity_hash_alg *alg = - libfsverity_find_hash_alg_by_num(alg_num); - - return alg ? alg->name : NULL; + hash_init(ctx); + hash_update(ctx, data, size); + hash_final(ctx, digest); } diff --git a/hash_algs.h b/hash_algs.h new file mode 100644 index 0000000..3e90f49 --- /dev/null +++ b/hash_algs.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +#ifndef HASH_ALGS_H +#define HASH_ALGS_H + +#include <stdio.h> + +#include "util.h" + +struct fsverity_hash_alg { + const char *name; + unsigned int digest_size; + unsigned int block_size; + struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg); +}; + +extern const struct fsverity_hash_alg fsverity_hash_algs[]; + +struct hash_ctx { + const struct fsverity_hash_alg *alg; + void (*init)(struct hash_ctx *ctx); + void (*update)(struct hash_ctx *ctx, const void *data, size_t size); + void (*final)(struct hash_ctx *ctx, u8 *out); + void (*free)(struct hash_ctx *ctx); +}; + +const struct fsverity_hash_alg *find_hash_alg_by_name(const char *name); +const struct fsverity_hash_alg *find_hash_alg_by_num(unsigned int num); +void show_all_hash_algs(FILE *fp); + +/* The hash algorithm that fsverity-utils assumes when none is specified */ +#define FS_VERITY_HASH_ALG_DEFAULT FS_VERITY_HASH_ALG_SHA256 + +/* + * Largest digest size among all hash algorithms supported by fs-verity. + * This can be increased if needed. + */ +#define FS_VERITY_MAX_DIGEST_SIZE 64 + +static inline struct hash_ctx *hash_create(const struct fsverity_hash_alg *alg) +{ + return alg->create_ctx(alg); +} + +static inline void hash_init(struct hash_ctx *ctx) +{ + ctx->init(ctx); +} + +static inline void hash_update(struct hash_ctx *ctx, + const void *data, size_t size) +{ + ctx->update(ctx, data, size); +} + +static inline void hash_final(struct hash_ctx *ctx, u8 *digest) +{ + ctx->final(ctx, digest); +} + +static inline void hash_free(struct hash_ctx *ctx) +{ + if (ctx) + ctx->free(ctx); +} + +void hash_full(struct hash_ctx *ctx, const void *data, size_t size, u8 *digest); + +#endif /* HASH_ALGS_H */ diff --git a/include/libfsverity.h b/include/libfsverity.h deleted file mode 100644 index 6c42e5e..0000000 --- a/include/libfsverity.h +++ /dev/null @@ -1,213 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * libfsverity API - * - * Copyright 2018 Google LLC - * Copyright (C) 2020 Facebook - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#ifndef LIBFSVERITY_H -#define LIBFSVERITY_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <errno.h> -#include <stddef.h> -#include <stdint.h> - -#define FSVERITY_UTILS_MAJOR_VERSION 1 -#define FSVERITY_UTILS_MINOR_VERSION 3 - -#define FS_VERITY_HASH_ALG_SHA256 1 -#define FS_VERITY_HASH_ALG_SHA512 2 - -/** - * struct libfsverity_merkle_tree_params - properties of a file's Merkle tree - * - * Zero this, then fill in at least @version and @file_size. - */ -struct libfsverity_merkle_tree_params { - - /** @version: must be 1 */ - uint32_t version; - - /** - * @hash_algorithm: one of FS_VERITY_HASH_ALG_*, or 0 to use the default - * of FS_VERITY_HASH_ALG_SHA256 - */ - uint32_t hash_algorithm; - - /** @file_size: the file size in bytes */ - uint64_t file_size; - - /** - * @block_size: the Merkle tree block size in bytes, or 0 to use the - * default of 4096 bytes - */ - uint32_t block_size; - - /** @salt_size: the salt size in bytes, or 0 if unsalted */ - uint32_t salt_size; - - /** @salt: pointer to the salt, or NULL if unsalted */ - const uint8_t *salt; - - /** @reserved1: must be 0 */ - uint64_t reserved1[8]; - - /** @reserved2: must be 0 */ - uintptr_t reserved2[8]; -}; - -struct libfsverity_digest { - uint16_t digest_algorithm; /* one of FS_VERITY_HASH_ALG_* */ - uint16_t digest_size; /* digest size in bytes */ - uint8_t digest[]; /* the actual digest */ -}; - -struct libfsverity_signature_params { - const char *keyfile; /* path to key file (PEM format) */ - const char *certfile; /* path to certificate (PEM format) */ - uint64_t reserved1[8]; /* must be 0 */ - uintptr_t reserved2[8]; /* must be 0 */ -}; - -/* - * libfsverity_read_fn_t - callback that incrementally provides a file's data - * @fd: the user-provided "file descriptor" (opaque to library) - * @buf: buffer into which to read the next chunk of the file's data - * @count: number of bytes to read in this chunk - * - * Must return 0 on success (all 'count' bytes read), or a negative errno value - * on failure. - */ -typedef int (*libfsverity_read_fn_t)(void *fd, void *buf, size_t count); - -/** - * libfsverity_compute_digest() - Compute digest of a file - * A fs-verity file digest is the hash of a file's fsverity_descriptor. - * Not to be confused with a traditional file digest computed over the - * entire file, or with the bare fsverity_descriptor::root_hash. - * @fd: context that will be passed to @read_fn - * @read_fn: a function that will read the data of the file - * @params: Pointer to the Merkle tree parameters - * @digest_ret: Pointer to pointer for computed digest. - * - * Returns: - * * 0 for success, -EINVAL for invalid input arguments, -ENOMEM if libfsverity - * failed to allocate memory, or an error returned by @read_fn. - * * digest_ret returns a pointer to the digest on success. The digest object - * is allocated by libfsverity and must be freed by the caller using free(). - */ -int -libfsverity_compute_digest(void *fd, libfsverity_read_fn_t read_fn, - const struct libfsverity_merkle_tree_params *params, - struct libfsverity_digest **digest_ret); - -/** - * libfsverity_sign_digest() - Sign previously computed digest of a file - * This signature is used by the filesystem to validate the signed file - * digest against a public key loaded into the .fs-verity kernel - * keyring, when CONFIG_FS_VERITY_BUILTIN_SIGNATURES is enabled. The - * signature is formatted as PKCS#7 stored in DER format. See - * Documentation/filesystems/fsverity.rst in the kernel source tree for - * further details. - * @digest: pointer to previously computed digest - * @sig_params: struct libfsverity_signature_params providing filenames of - * the keyfile and certificate file. Reserved fields must be zero. - * @sig_ret: Pointer to pointer for signed digest - * @sig_size_ret: Pointer to size of signed return digest - * - * Return: - * * 0 for success, -EINVAL for invalid input arguments or if the cryptographic - * operations to sign the digest failed, -EBADMSG if the key and/or - * certificate file is invalid, or another negative errno value. - * * sig_ret returns a pointer to the signed digest on success. This object - * is allocated by libfsverity and must be freed by the caller using free(). - * * sig_size_ret returns the size (in bytes) of the signed digest on success. - */ -int -libfsverity_sign_digest(const struct libfsverity_digest *digest, - const struct libfsverity_signature_params *sig_params, - uint8_t **sig_ret, size_t *sig_size_ret); - -/** - * libfsverity_enable() - Enable fs-verity on a file - * @fd: read-only file descriptor to the file - * @params: pointer to the Merkle tree parameters - * - * This is a simple wrapper around the FS_IOC_ENABLE_VERITY ioctl. - * - * Return: 0 on success, -EINVAL for invalid arguments, or a negative errno - * value from the FS_IOC_ENABLE_VERITY ioctl. See - * Documentation/filesystems/fsverity.rst in the kernel source tree for - * the possible error codes from FS_IOC_ENABLE_VERITY. - */ -int -libfsverity_enable(int fd, const struct libfsverity_merkle_tree_params *params); - -/** - * libfsverity_enable_with_sig() - Enable fs-verity on a file, with a signature - * @fd: read-only file descriptor to the file - * @params: pointer to the Merkle tree parameters - * @sig: pointer to the file's signature - * @sig_size: size of the file's signature in bytes - * - * Like libfsverity_enable(), but allows specifying a built-in signature (i.e. a - * singature created with libfsverity_sign_digest()) to associate with the file. - * This is only needed if the in-kernel signature verification support is being - * used; it is not needed if signatures are being verified in userspace. - * - * If @sig is NULL and @sig_size is 0, this is the same as libfsverity_enable(). - * - * Return: See libfsverity_enable(). - */ -int -libfsverity_enable_with_sig(int fd, - const struct libfsverity_merkle_tree_params *params, - const uint8_t *sig, size_t sig_size); - -/** - * libfsverity_find_hash_alg_by_name() - Find hash algorithm by name - * @name: Pointer to name of hash algorithm - * - * Return: The hash algorithm number, or zero if not found. - */ -uint32_t libfsverity_find_hash_alg_by_name(const char *name); - -/** - * libfsverity_get_digest_size() - Get size of digest for a given algorithm - * @alg_num: Number of hash algorithm - * - * Return: size of digest in bytes, or -1 if algorithm is unknown. - */ -int libfsverity_get_digest_size(uint32_t alg_num); - -/** - * libfsverity_get_hash_name() - Get name of hash algorithm by number - * @alg_num: Number of hash algorithm - * - * Return: The name of the hash algorithm, or NULL if algorithm is unknown. - */ -const char *libfsverity_get_hash_name(uint32_t alg_num); - -/** - * libfsverity_set_error_callback() - Set callback to handle error messages - * @cb: the callback function. - * - * If a callback is already set, it is replaced. @cb may be NULL in order to - * remove the existing callback. - */ -void libfsverity_set_error_callback(void (*cb)(const char *msg)); - -#ifdef __cplusplus -} -#endif - -#endif /* LIBFSVERITY_H */ diff --git a/lib/compute_digest.c b/lib/compute_digest.c deleted file mode 100644 index a4f649c..0000000 --- a/lib/compute_digest.c +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Implementation of libfsverity_compute_digest(). - * - * Copyright 2018 Google LLC - * Copyright (C) 2020 Facebook - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "lib_private.h" - -#include <stdlib.h> -#include <string.h> - -#define FS_VERITY_MAX_LEVELS 64 - -struct block_buffer { - u32 filled; - u8 *data; -}; - -/* - * Hash a block, writing the result to the next level's pending block buffer. - * Returns true if the next level's block became full, else false. - */ -static bool hash_one_block(struct hash_ctx *hash, struct block_buffer *cur, - u32 block_size, const u8 *salt, u32 salt_size) -{ - struct block_buffer *next = cur + 1; - - /* Zero-pad the block if it's shorter than block_size. */ - memset(&cur->data[cur->filled], 0, block_size - cur->filled); - - libfsverity_hash_init(hash); - libfsverity_hash_update(hash, salt, salt_size); - libfsverity_hash_update(hash, cur->data, block_size); - libfsverity_hash_final(hash, &next->data[next->filled]); - - next->filled += hash->alg->digest_size; - cur->filled = 0; - - return next->filled + hash->alg->digest_size > block_size; -} - -/* - * Compute the file's Merkle tree root hash using the given hash algorithm, - * block size, and salt. - */ -static int compute_root_hash(void *fd, libfsverity_read_fn_t read_fn, - u64 file_size, struct hash_ctx *hash, - u32 block_size, const u8 *salt, u32 salt_size, - u8 *root_hash) -{ - const u32 hashes_per_block = block_size / hash->alg->digest_size; - const u32 padded_salt_size = roundup(salt_size, hash->alg->block_size); - u8 *padded_salt = NULL; - u64 blocks; - int num_levels = 0; - int level; - struct block_buffer _buffers[1 + FS_VERITY_MAX_LEVELS + 1] = {}; - struct block_buffer *buffers = &_buffers[1]; - u64 offset; - int err = 0; - - /* Root hash of empty file is all 0's */ - if (file_size == 0) { - memset(root_hash, 0, hash->alg->digest_size); - return 0; - } - - if (salt_size != 0) { - padded_salt = libfsverity_zalloc(padded_salt_size); - if (!padded_salt) - return -ENOMEM; - memcpy(padded_salt, salt, salt_size); - } - - /* Compute number of levels */ - for (blocks = DIV_ROUND_UP(file_size, block_size); blocks > 1; - blocks = DIV_ROUND_UP(blocks, hashes_per_block)) { - if (WARN_ON(num_levels >= FS_VERITY_MAX_LEVELS)) { - err = -EINVAL; - goto out; - } - num_levels++; - } - - /* - * Allocate the block buffers. Buffer "-1" is for data blocks. - * Buffers 0 <= level < num_levels are for the actual tree levels. - * Buffer 'num_levels' is for the root hash. - */ - for (level = -1; level < num_levels; level++) { - buffers[level].data = libfsverity_zalloc(block_size); - if (!buffers[level].data) { - err = -ENOMEM; - goto out; - } - } - buffers[num_levels].data = root_hash; - - /* Hash each data block, also hashing the tree blocks as they fill up */ - for (offset = 0; offset < file_size; offset += block_size) { - buffers[-1].filled = min(block_size, file_size - offset); - - err = read_fn(fd, buffers[-1].data, buffers[-1].filled); - if (err) { - libfsverity_error_msg("error reading file"); - goto out; - } - - level = -1; - while (hash_one_block(hash, &buffers[level], block_size, - padded_salt, padded_salt_size)) { - level++; - if (WARN_ON(level >= num_levels)) { - err = -EINVAL; - goto out; - } - } - } - /* Finish all nonempty pending tree blocks */ - for (level = 0; level < num_levels; level++) { - if (buffers[level].filled != 0) - hash_one_block(hash, &buffers[level], block_size, - padded_salt, padded_salt_size); - } - - /* Root hash was filled by the last call to hash_one_block() */ - if (WARN_ON(buffers[num_levels].filled != hash->alg->digest_size)) { - err = -EINVAL; - goto out; - } - err = 0; -out: - for (level = -1; level < num_levels; level++) - free(buffers[level].data); - free(padded_salt); - return err; -} - -LIBEXPORT int -libfsverity_compute_digest(void *fd, libfsverity_read_fn_t read_fn, - const struct libfsverity_merkle_tree_params *params, - struct libfsverity_digest **digest_ret) -{ - u32 alg_num; - u32 block_size; - const struct fsverity_hash_alg *hash_alg; - struct hash_ctx *hash = NULL; - struct libfsverity_digest *digest; - struct fsverity_descriptor desc; - int err; - - if (!read_fn || !params || !digest_ret) { - libfsverity_error_msg("missing required parameters for compute_digest"); - return -EINVAL; - } - if (params->version != 1) { - libfsverity_error_msg("unsupported version (%u)", - params->version); - return -EINVAL; - } - - alg_num = params->hash_algorithm ?: FS_VERITY_HASH_ALG_DEFAULT; - block_size = params->block_size ?: FS_VERITY_BLOCK_SIZE_DEFAULT; - - if (!is_power_of_2(block_size)) { - libfsverity_error_msg("unsupported block size (%u)", - block_size); - return -EINVAL; - } - if (params->salt_size > sizeof(desc.salt)) { - libfsverity_error_msg("unsupported salt size (%u)", - params->salt_size); - return -EINVAL; - } - if (params->salt_size && !params->salt) { - libfsverity_error_msg("salt_size specified, but salt is NULL"); - return -EINVAL; - } - if (!libfsverity_mem_is_zeroed(params->reserved1, - sizeof(params->reserved1)) || - !libfsverity_mem_is_zeroed(params->reserved2, - sizeof(params->reserved2))) { - libfsverity_error_msg("reserved bits set in merkle_tree_params"); - return -EINVAL; - } - - hash_alg = libfsverity_find_hash_alg_by_num(alg_num); - if (!hash_alg) { - libfsverity_error_msg("unknown hash algorithm: %u", alg_num); - return -EINVAL; - } - - if (block_size < 2 * hash_alg->digest_size) { - libfsverity_error_msg("block size (%u) too small for hash algorithm %s", - block_size, hash_alg->name); - return -EINVAL; - } - - hash = hash_alg->create_ctx(hash_alg); - if (!hash) - return -ENOMEM; - - memset(&desc, 0, sizeof(desc)); - desc.version = 1; - desc.hash_algorithm = alg_num; - desc.log_blocksize = ilog2(block_size); - desc.data_size = cpu_to_le64(params->file_size); - if (params->salt_size != 0) { - memcpy(desc.salt, params->salt, params->salt_size); - desc.salt_size = params->salt_size; - } - - err = compute_root_hash(fd, read_fn, params->file_size, hash, - block_size, params->salt, - params->salt_size, desc.root_hash); - if (err) - goto out; - - digest = libfsverity_zalloc(sizeof(*digest) + hash_alg->digest_size); - if (!digest) { - err = -ENOMEM; - goto out; - } - digest->digest_algorithm = alg_num; - digest->digest_size = hash_alg->digest_size; - libfsverity_hash_full(hash, &desc, sizeof(desc), digest->digest); - *digest_ret = digest; - err = 0; -out: - libfsverity_free_hash_ctx(hash); - return err; -} diff --git a/lib/enable.c b/lib/enable.c deleted file mode 100644 index 2478077..0000000 --- a/lib/enable.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Implementation of libfsverity_enable() and libfsverity_enable_with_sig(). - * - * Copyright 2020 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "lib_private.h" - -#include <sys/ioctl.h> - -LIBEXPORT int -libfsverity_enable(int fd, const struct libfsverity_merkle_tree_params *params) -{ - return libfsverity_enable_with_sig(fd, params, NULL, 0); -} - -LIBEXPORT int -libfsverity_enable_with_sig(int fd, - const struct libfsverity_merkle_tree_params *params, - const uint8_t *sig, size_t sig_size) -{ - struct fsverity_enable_arg arg = {}; - - if (!params) { - libfsverity_error_msg("missing required parameters for enable"); - return -EINVAL; - } - - if (params->version != 1) { - libfsverity_error_msg("unsupported version (%u)", - params->version); - return -EINVAL; - } - - arg.version = 1; - arg.hash_algorithm = - params->hash_algorithm ?: FS_VERITY_HASH_ALG_DEFAULT; - arg.block_size = - params->block_size ?: FS_VERITY_BLOCK_SIZE_DEFAULT; - arg.salt_size = params->salt_size; - arg.salt_ptr = (uintptr_t)params->salt; - arg.sig_size = sig_size; - arg.sig_ptr = (uintptr_t)sig; - - if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) != 0) - return -errno; - return 0; -} diff --git a/lib/lib_private.h b/lib/lib_private.h deleted file mode 100644 index 7768eea..0000000 --- a/lib/lib_private.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Private header for libfsverity - * - * Copyright 2020 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ -#ifndef LIB_LIB_PRIVATE_H -#define LIB_LIB_PRIVATE_H - -#include "libfsverity.h" -#include "../common/common_defs.h" -#include "../common/fsverity_uapi.h" - -#include <stdarg.h> - -#define LIBEXPORT __attribute__((visibility("default"))) - -/* The hash algorithm that libfsverity assumes when none is specified */ -#define FS_VERITY_HASH_ALG_DEFAULT FS_VERITY_HASH_ALG_SHA256 - -/* The block size that libfsverity assumes when none is specified */ -#define FS_VERITY_BLOCK_SIZE_DEFAULT 4096 - -/* hash_algs.c */ - -struct fsverity_hash_alg { - const char *name; - unsigned int digest_size; - unsigned int block_size; - struct hash_ctx *(*create_ctx)(const struct fsverity_hash_alg *alg); -}; - -const struct fsverity_hash_alg *libfsverity_find_hash_alg_by_num(u32 alg_num); - -struct hash_ctx { - const struct fsverity_hash_alg *alg; - void (*init)(struct hash_ctx *ctx); - void (*update)(struct hash_ctx *ctx, const void *data, size_t size); - void (*final)(struct hash_ctx *ctx, u8 *out); - void (*free)(struct hash_ctx *ctx); -}; - -void libfsverity_hash_init(struct hash_ctx *ctx); -void libfsverity_hash_update(struct hash_ctx *ctx, const void *data, - size_t size); -void libfsverity_hash_final(struct hash_ctx *ctx, u8 *digest); -void libfsverity_hash_full(struct hash_ctx *ctx, const void *data, size_t size, - u8 *digest); -void libfsverity_free_hash_ctx(struct hash_ctx *ctx); - -/* utils.c */ - -void *libfsverity_zalloc(size_t size); -void *libfsverity_memdup(const void *mem, size_t size); - -__cold void -libfsverity_do_error_msg(const char *format, va_list va, int err); - -__printf(1, 2) __cold void -libfsverity_error_msg(const char *format, ...); - -__printf(1, 2) __cold void -libfsverity_error_msg_errno(const char *format, ...); - -__cold void -libfsverity_warn_on(const char *condition, const char *file, int line); - -#define WARN_ON(condition) \ -({ \ - bool c = (condition); \ - \ - if (c) \ - libfsverity_warn_on(#condition, __FILE__, __LINE__); \ - c; \ -}) - -__cold void -libfsverity_bug_on(const char *condition, const char *file, int line); - -#define BUG_ON(condition) \ -({ \ - bool c = (condition); \ - \ - if (c) \ - libfsverity_bug_on(#condition, __FILE__, __LINE__); \ - c; \ -}) - -bool libfsverity_mem_is_zeroed(const void *mem, size_t size); - -#endif /* LIB_LIB_PRIVATE_H */ diff --git a/lib/libfsverity.pc.in b/lib/libfsverity.pc.in deleted file mode 100644 index be3ef44..0000000 --- a/lib/libfsverity.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@PREFIX@ -libdir=@LIBDIR@ -includedir=@INCDIR@ - -Name: libfsverity -Description: fs-verity library -Version: 1.3 -Libs: -L${libdir} -lfsverity -Requires.private: libcrypto -Cflags: -I${includedir} diff --git a/lib/sign_digest.c b/lib/sign_digest.c deleted file mode 100644 index 9a35256..0000000 --- a/lib/sign_digest.c +++ /dev/null @@ -1,390 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Implementation of libfsverity_sign_digest(). - * - * Copyright 2018 Google LLC - * Copyright (C) 2020 Facebook - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "lib_private.h" - -#include <limits.h> -#include <openssl/bio.h> -#include <openssl/err.h> -#include <openssl/pem.h> -#include <openssl/pkcs7.h> -#include <string.h> - -static int print_openssl_err_cb(const char *str, - size_t len __attribute__((unused)), - void *u __attribute__((unused))) -{ - libfsverity_error_msg("%s", str); - return 1; -} - -static void __printf(1, 2) __cold -error_msg_openssl(const char *format, ...) -{ - int saved_errno = errno; - va_list va; - - va_start(va, format); - libfsverity_do_error_msg(format, va, 0); - va_end(va); - - if (ERR_peek_error() == 0) - return; - - libfsverity_error_msg("OpenSSL library errors:"); - ERR_print_errors_cb(print_openssl_err_cb, NULL); - errno = saved_errno; -} - -/* Read a PEM PKCS#8 formatted private key */ -static int read_private_key(const char *keyfile, EVP_PKEY **pkey_ret) -{ - BIO *bio; - EVP_PKEY *pkey; - int err; - - errno = 0; - bio = BIO_new_file(keyfile, "r"); - if (!bio) { - error_msg_openssl("can't open '%s' for reading", keyfile); - return errno ? -errno : -EIO; - } - - pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); - if (!pkey) { - error_msg_openssl("Failed to parse private key file '%s'.\n" - " Note: it must be in PEM PKCS#8 format.", - keyfile); - err = -EBADMSG; - goto out; - } - *pkey_ret = pkey; - err = 0; -out: - BIO_free(bio); - return err; -} - -/* Read a PEM X.509 formatted certificate */ -static int read_certificate(const char *certfile, X509 **cert_ret) -{ - BIO *bio; - X509 *cert; - int err; - - errno = 0; - bio = BIO_new_file(certfile, "r"); - if (!bio) { - error_msg_openssl("can't open '%s' for reading", certfile); - return errno ? -errno : -EIO; - } - cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); - if (!cert) { - error_msg_openssl("Failed to parse X.509 certificate file '%s'.\n" - " Note: it must be in PEM format.", - certfile); - err = -EBADMSG; - goto out; - } - *cert_ret = cert; - err = 0; -out: - BIO_free(bio); - return err; -} - -#ifdef OPENSSL_IS_BORINGSSL - -static int sign_pkcs7(const void *data_to_sign, size_t data_size, - EVP_PKEY *pkey, X509 *cert, const EVP_MD *md, - u8 **sig_ret, size_t *sig_size_ret) -{ - BIGNUM *serial; - CBB out, outer_seq, wrapped_seq, seq, digest_algos_set, digest_algo, - null, content_info, issuer_and_serial, signer_infos, - signer_info, sign_algo, signature; - EVP_MD_CTX md_ctx; - u8 *name_der = NULL, *sig = NULL, *pkcs7_data = NULL; - size_t pkcs7_data_len, sig_len; - int name_der_len, sig_nid; - int err; - - EVP_MD_CTX_init(&md_ctx); - serial = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), NULL); - - if (!CBB_init(&out, 1024)) { - error_msg_openssl("out of memory"); - err = -ENOMEM; - goto out; - } - - name_der_len = i2d_X509_NAME(X509_get_subject_name(cert), &name_der); - if (name_der_len < 0) { - error_msg_openssl("i2d_X509_NAME failed"); - err = -EINVAL; - goto out; - } - - if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey)) { - error_msg_openssl("EVP_DigestSignInit failed"); - err = -EINVAL; - goto out; - } - - sig_len = EVP_PKEY_size(pkey); - sig = libfsverity_zalloc(sig_len); - if (!sig) { - err = -ENOMEM; - goto out; - } - if (!EVP_DigestSign(&md_ctx, sig, &sig_len, data_to_sign, data_size)) { - error_msg_openssl("EVP_DigestSign failed"); - err = -EINVAL; - goto out; - } - - sig_nid = EVP_PKEY_id(pkey); - /* To mirror OpenSSL behaviour, always use |NID_rsaEncryption| with RSA - * rather than the combined hash+pkey NID. */ - if (sig_nid != NID_rsaEncryption) { - OBJ_find_sigid_by_algs(&sig_nid, EVP_MD_type(md), - EVP_PKEY_id(pkey)); - } - - // See https://tools.ietf.org/html/rfc2315#section-7 - if (!CBB_add_asn1(&out, &outer_seq, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) || - !CBB_add_asn1(&outer_seq, &wrapped_seq, CBS_ASN1_CONTEXT_SPECIFIC | - CBS_ASN1_CONSTRUCTED | 0) || - // See https://tools.ietf.org/html/rfc2315#section-9.1 - !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) || - !CBB_add_asn1_uint64(&seq, 1 /* version */) || - !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) || - !CBB_add_asn1(&digest_algos_set, &digest_algo, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) || - !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) || - !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&content_info, NID_pkcs7_data) || - !CBB_add_asn1(&seq, &signer_infos, CBS_ASN1_SET) || - !CBB_add_asn1(&signer_infos, &signer_info, CBS_ASN1_SEQUENCE) || - !CBB_add_asn1_uint64(&signer_info, 1 /* version */) || - !CBB_add_asn1(&signer_info, &issuer_and_serial, - CBS_ASN1_SEQUENCE) || - !CBB_add_bytes(&issuer_and_serial, name_der, name_der_len) || - !BN_marshal_asn1(&issuer_and_serial, serial) || - !CBB_add_asn1(&signer_info, &digest_algo, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) || - !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) || - !CBB_add_asn1(&signer_info, &sign_algo, CBS_ASN1_SEQUENCE) || - !OBJ_nid2cbb(&sign_algo, sig_nid) || - !CBB_add_asn1(&sign_algo, &null, CBS_ASN1_NULL) || - !CBB_add_asn1(&signer_info, &signature, CBS_ASN1_OCTETSTRING) || - !CBB_add_bytes(&signature, sig, sig_len) || - !CBB_finish(&out, &pkcs7_data, &pkcs7_data_len)) { - error_msg_openssl("failed to construct PKCS#7 data"); - err = -EINVAL; - goto out; - } - - *sig_ret = libfsverity_memdup(pkcs7_data, pkcs7_data_len); - if (!*sig_ret) { - err = -ENOMEM; - goto out; - } - *sig_size_ret = pkcs7_data_len; - err = 0; -out: - BN_free(serial); - EVP_MD_CTX_cleanup(&md_ctx); - CBB_cleanup(&out); - free(sig); - OPENSSL_free(name_der); - OPENSSL_free(pkcs7_data); - return err; -} - -#else /* OPENSSL_IS_BORINGSSL */ - -static BIO *new_mem_buf(const void *buf, size_t size) -{ - BIO *bio; - - if (WARN_ON(size > INT_MAX)) - return NULL; - - /* - * Prior to OpenSSL 1.1.0, BIO_new_mem_buf() took a non-const pointer, - * despite still marking the resulting bio as read-only. So cast away - * the const to avoid a compiler warning with older OpenSSL versions. - */ - bio = BIO_new_mem_buf((void *)buf, size); - if (!bio) - error_msg_openssl("out of memory"); - return bio; -} - -static int sign_pkcs7(const void *data_to_sign, size_t data_size, - EVP_PKEY *pkey, X509 *cert, const EVP_MD *md, - u8 **sig_ret, size_t *sig_size_ret) -{ - /* - * PKCS#7 signing flags: - * - * - PKCS7_BINARY signing binary data, so skip MIME translation - * - * - PKCS7_DETACHED omit the signed data (include signature only) - * - * - PKCS7_NOATTR omit extra authenticated attributes, such as - * SMIMECapabilities - * - * - PKCS7_NOCERTS omit the signer's certificate - * - * - PKCS7_PARTIAL PKCS7_sign() creates a handle only, then - * PKCS7_sign_add_signer() can add a signer later. - * This is necessary to change the message digest - * algorithm from the default of SHA-1. Requires - * OpenSSL 1.0.0 or later. - */ - int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR | - PKCS7_NOCERTS | PKCS7_PARTIAL; - u8 *sig; - u32 sig_size; - BIO *bio = NULL; - PKCS7 *p7 = NULL; - int err; - - bio = new_mem_buf(data_to_sign, data_size); - if (!bio) { - err = -ENOMEM; - goto out; - } - - p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags); - if (!p7) { - error_msg_openssl("failed to initialize PKCS#7 signature object"); - err = -EINVAL; - goto out; - } - - if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) { - error_msg_openssl("failed to add signer to PKCS#7 signature object"); - err = -EINVAL; - goto out; - } - - if (PKCS7_final(p7, bio, pkcs7_flags) != 1) { - error_msg_openssl("failed to finalize PKCS#7 signature"); - err = -EINVAL; - goto out; - } - - BIO_free(bio); - bio = BIO_new(BIO_s_mem()); - if (!bio) { - error_msg_openssl("out of memory"); - err = -ENOMEM; - goto out; - } - - if (i2d_PKCS7_bio(bio, p7) != 1) { - error_msg_openssl("failed to DER-encode PKCS#7 signature object"); - err = -EINVAL; - goto out; - } - - sig_size = BIO_get_mem_data(bio, &sig); - *sig_ret = libfsverity_memdup(sig, sig_size); - if (!*sig_ret) { - err = -ENOMEM; - goto out; - } - *sig_size_ret = sig_size; - err = 0; -out: - PKCS7_free(p7); - BIO_free(bio); - return err; -} - -#endif /* !OPENSSL_IS_BORINGSSL */ - -LIBEXPORT int -libfsverity_sign_digest(const struct libfsverity_digest *digest, - const struct libfsverity_signature_params *sig_params, - u8 **sig_ret, size_t *sig_size_ret) -{ - const struct fsverity_hash_alg *hash_alg; - EVP_PKEY *pkey = NULL; - X509 *cert = NULL; - const EVP_MD *md; - struct fsverity_formatted_digest *d = NULL; - int err; - - if (!digest || !sig_params || !sig_ret || !sig_size_ret) { - libfsverity_error_msg("missing required parameters for sign_digest"); - return -EINVAL; - } - - if (!sig_params->keyfile || !sig_params->certfile) { - libfsverity_error_msg("keyfile and certfile must be specified"); - return -EINVAL; - } - - if (!libfsverity_mem_is_zeroed(sig_params->reserved1, - sizeof(sig_params->reserved1)) || - !libfsverity_mem_is_zeroed(sig_params->reserved2, - sizeof(sig_params->reserved2))) { - libfsverity_error_msg("reserved bits set in signature_params"); - return -EINVAL; - } - - hash_alg = libfsverity_find_hash_alg_by_num(digest->digest_algorithm); - if (!hash_alg || digest->digest_size != hash_alg->digest_size) { - libfsverity_error_msg("malformed fsverity digest"); - return -EINVAL; - } - - err = read_private_key(sig_params->keyfile, &pkey); - if (err) - goto out; - - err = read_certificate(sig_params->certfile, &cert); - if (err) - goto out; - - OpenSSL_add_all_digests(); - md = EVP_get_digestbyname(hash_alg->name); - if (!md) { - libfsverity_error_msg("'%s' algorithm not found in OpenSSL library", - hash_alg->name); - err = -ENOPKG; - goto out; - } - - d = libfsverity_zalloc(sizeof(*d) + digest->digest_size); - if (!d) { - err = -ENOMEM; - goto out; - } - memcpy(d->magic, "FSVerity", 8); - d->digest_algorithm = cpu_to_le16(digest->digest_algorithm); - d->digest_size = cpu_to_le16(digest->digest_size); - memcpy(d->digest, digest->digest, digest->digest_size); - - err = sign_pkcs7(d, sizeof(*d) + digest->digest_size, - pkey, cert, md, sig_ret, sig_size_ret); - out: - EVP_PKEY_free(pkey); - X509_free(cert); - free(d); - return err; -} diff --git a/lib/utils.c b/lib/utils.c deleted file mode 100644 index 036dd60..0000000 --- a/lib/utils.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Utility functions for libfsverity - * - * Copyright 2020 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "lib_private.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -static void *xmalloc(size_t size) -{ - void *p = malloc(size); - - if (!p) - libfsverity_error_msg("out of memory (tried to allocate %zu bytes)", - size); - return p; -} - -void *libfsverity_zalloc(size_t size) -{ - void *p = xmalloc(size); - - if (!p) - return NULL; - return memset(p, 0, size); -} - -void *libfsverity_memdup(const void *mem, size_t size) -{ - void *p = xmalloc(size); - - if (!p) - return NULL; - return memcpy(p, mem, size); -} - -static void (*libfsverity_error_cb)(const char *msg); - -LIBEXPORT void -libfsverity_set_error_callback(void (*cb)(const char *msg)) -{ - libfsverity_error_cb = cb; -} - -#ifdef _WIN32 -static char *strerror_r(int errnum, char *buf, size_t buflen) -{ - strerror_s(buf, buflen, errnum); - - return buf; -} -#endif - -void libfsverity_do_error_msg(const char *format, va_list va, int err) -{ - int saved_errno = errno; - char *msg = NULL; - - if (!libfsverity_error_cb) - return; - - if (vasprintf(&msg, format, va) < 0) - goto out; - - if (err) { - char *msg2 = NULL; - char errbuf[64]; - - if (asprintf(&msg2, "%s: %s", msg, - strerror_r(err, errbuf, sizeof(errbuf))) < 0) - goto out2; - free(msg); - msg = msg2; - } - (*libfsverity_error_cb)(msg); -out2: - free(msg); -out: - errno = saved_errno; -} - -void libfsverity_error_msg(const char *format, ...) -{ - va_list va; - - va_start(va, format); - libfsverity_do_error_msg(format, va, 0); - va_end(va); -} - -void libfsverity_error_msg_errno(const char *format, ...) -{ - va_list va; - - va_start(va, format); - libfsverity_do_error_msg(format, va, errno); - va_end(va); -} - -void libfsverity_warn_on(const char *condition, const char *file, int line) -{ - fprintf(stderr, "libfsverity internal error! %s at %s:%d\n", - condition, file, line); -} - -void libfsverity_bug_on(const char *condition, const char *file, int line) -{ - fprintf(stderr, "libfsverity internal error! %s at %s:%d\n" - "Non-recoverable, aborting program.\n", condition, file, line); - abort(); -} - -bool libfsverity_mem_is_zeroed(const void *mem, size_t size) -{ - const u8 *p = mem; - size_t i; - - for (i = 0; i < size; i++) { - if (p[i]) - return false; - } - return true; -} diff --git a/programs/cmd_digest.c b/programs/cmd_digest.c deleted file mode 100644 index 1a3c769..0000000 --- a/programs/cmd_digest.c +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * The 'fsverity digest' command - * - * Copyright 2020 Microsoft - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "fsverity.h" - -#include <fcntl.h> -#include <getopt.h> - -static const struct option longopts[] = { - {"hash-alg", required_argument, NULL, OPT_HASH_ALG}, - {"block-size", required_argument, NULL, OPT_BLOCK_SIZE}, - {"salt", required_argument, NULL, OPT_SALT}, - {"compact", no_argument, NULL, OPT_COMPACT}, - {"for-builtin-sig", no_argument, NULL, OPT_FOR_BUILTIN_SIG}, - {NULL, 0, NULL, 0} -}; - -/* - * Compute the fs-verity digest of the given file(s), for offline signing. - */ -int fsverity_cmd_digest(const struct fsverity_command *cmd, - int argc, char *argv[]) -{ - struct filedes file = { .fd = -1 }; - struct libfsverity_merkle_tree_params tree_params = { .version = 1 }; - bool compact = false, for_builtin_sig = false; - int status; - int c; - - while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) { - switch (c) { - case OPT_HASH_ALG: - case OPT_BLOCK_SIZE: - case OPT_SALT: - if (!parse_tree_param(c, optarg, &tree_params)) - goto out_usage; - break; - case OPT_COMPACT: - compact = true; - break; - case OPT_FOR_BUILTIN_SIG: - for_builtin_sig = true; - break; - default: - goto out_usage; - } - } - - argv += optind; - argc -= optind; - - if (argc < 1) - goto out_usage; - - for (int i = 0; i < argc; i++) { - struct fsverity_formatted_digest *d = NULL; - struct libfsverity_digest *digest = NULL; - char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + - sizeof(*d) * 2 + 1]; - - if (!open_file(&file, argv[i], O_RDONLY, 0)) - goto out_err; - - if (!get_file_size(&file, &tree_params.file_size)) - goto out_err; - - if (libfsverity_compute_digest(&file, read_callback, - &tree_params, &digest) != 0) { - error_msg("failed to compute digest"); - goto out_err; - } - - ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE); - - if (for_builtin_sig) { - /* - * Format the digest for use with the built-in signature - * support. - */ - d = xzalloc(sizeof(*d) + digest->digest_size); - memcpy(d->magic, "FSVerity", 8); - d->digest_algorithm = - cpu_to_le16(digest->digest_algorithm); - d->digest_size = cpu_to_le16(digest->digest_size); - memcpy(d->digest, digest->digest, digest->digest_size); - - bin2hex((const u8 *)d, sizeof(*d) + digest->digest_size, - digest_hex); - } else { - bin2hex(digest->digest, digest->digest_size, - digest_hex); - } - - if (compact) - printf("%s\n", digest_hex); - else if (for_builtin_sig) - printf("%s %s\n", digest_hex, argv[i]); - else - printf("%s:%s %s\n", - libfsverity_get_hash_name(digest->digest_algorithm), - digest_hex, argv[i]); - - filedes_close(&file); - free(digest); - free(d); - } - status = 0; -out: - destroy_tree_params(&tree_params); - return status; - -out_err: - filedes_close(&file); - status = 1; - goto out; - -out_usage: - usage(cmd, stderr); - status = 2; - goto out; -} diff --git a/programs/cmd_sign.c b/programs/cmd_sign.c deleted file mode 100644 index 47ba6a2..0000000 --- a/programs/cmd_sign.c +++ /dev/null @@ -1,133 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * The 'fsverity sign' command - * - * Copyright 2018 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "fsverity.h" - -#include <fcntl.h> -#include <getopt.h> - -static bool write_signature(const char *filename, const u8 *sig, u32 sig_size) -{ - struct filedes file; - bool ok; - - if (!open_file(&file, filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) - return false; - ok = full_write(&file, sig, sig_size); - ok &= filedes_close(&file); - return ok; -} - -static const struct option longopts[] = { - {"hash-alg", required_argument, NULL, OPT_HASH_ALG}, - {"block-size", required_argument, NULL, OPT_BLOCK_SIZE}, - {"salt", required_argument, NULL, OPT_SALT}, - {"key", required_argument, NULL, OPT_KEY}, - {"cert", required_argument, NULL, OPT_CERT}, - {NULL, 0, NULL, 0} -}; - -/* Sign a file for fs-verity by computing its digest, then signing it. */ -int fsverity_cmd_sign(const struct fsverity_command *cmd, - int argc, char *argv[]) -{ - struct filedes file = { .fd = -1 }; - struct libfsverity_merkle_tree_params tree_params = { .version = 1 }; - struct libfsverity_signature_params sig_params = {}; - struct libfsverity_digest *digest = NULL; - char digest_hex[FS_VERITY_MAX_DIGEST_SIZE * 2 + 1]; - u8 *sig = NULL; - size_t sig_size; - int status; - int c; - - while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) { - switch (c) { - case OPT_HASH_ALG: - case OPT_BLOCK_SIZE: - case OPT_SALT: - if (!parse_tree_param(c, optarg, &tree_params)) - goto out_usage; - break; - case OPT_KEY: - if (sig_params.keyfile != NULL) { - error_msg("--key can only be specified once"); - goto out_usage; - } - sig_params.keyfile = optarg; - break; - case OPT_CERT: - if (sig_params.certfile != NULL) { - error_msg("--cert can only be specified once"); - goto out_usage; - } - sig_params.certfile = optarg; - break; - default: - goto out_usage; - } - } - - argv += optind; - argc -= optind; - - if (argc != 2) - goto out_usage; - - if (sig_params.keyfile == NULL) { - error_msg("Missing --key argument"); - goto out_usage; - } - if (sig_params.certfile == NULL) - sig_params.certfile = sig_params.keyfile; - - if (!open_file(&file, argv[0], O_RDONLY, 0)) - goto out_err; - - if (!get_file_size(&file, &tree_params.file_size)) - goto out_err; - - if (libfsverity_compute_digest(&file, read_callback, - &tree_params, &digest) != 0) { - error_msg("failed to compute digest"); - goto out_err; - } - - if (libfsverity_sign_digest(digest, &sig_params, - &sig, &sig_size) != 0) { - error_msg("failed to sign digest"); - goto out_err; - } - - if (!write_signature(argv[1], sig, sig_size)) - goto out_err; - - ASSERT(digest->digest_size <= FS_VERITY_MAX_DIGEST_SIZE); - bin2hex(digest->digest, digest->digest_size, digest_hex); - printf("Signed file '%s' (%s:%s)\n", argv[0], - libfsverity_get_hash_name(digest->digest_algorithm), digest_hex); - status = 0; -out: - filedes_close(&file); - destroy_tree_params(&tree_params); - free(digest); - free(sig); - return status; - -out_err: - status = 1; - goto out; - -out_usage: - usage(cmd, stderr); - status = 2; - goto out; -} diff --git a/programs/fsverity.h b/programs/fsverity.h deleted file mode 100644 index 45c4fe1..0000000 --- a/programs/fsverity.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Private header for the 'fsverity' program - * - * Copyright 2018 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ -#ifndef PROGRAMS_FSVERITY_H -#define PROGRAMS_FSVERITY_H - -#include "utils.h" -#include "../common/fsverity_uapi.h" - -/* - * Largest digest size among all hash algorithms supported by fs-verity. - * This can be increased if needed. - */ -#define FS_VERITY_MAX_DIGEST_SIZE 64 - -enum { - OPT_BLOCK_SIZE, - OPT_CERT, - OPT_COMPACT, - OPT_FOR_BUILTIN_SIG, - OPT_HASH_ALG, - OPT_KEY, - OPT_SALT, - OPT_SIGNATURE, -}; - -struct fsverity_command; - -/* cmd_digest.c */ -int fsverity_cmd_digest(const struct fsverity_command *cmd, - int argc, char *argv[]); - -/* cmd_enable.c */ -int fsverity_cmd_enable(const struct fsverity_command *cmd, - int argc, char *argv[]); - -/* cmd_measure.c */ -int fsverity_cmd_measure(const struct fsverity_command *cmd, - int argc, char *argv[]); - -/* cmd_sign.c */ -int fsverity_cmd_sign(const struct fsverity_command *cmd, - int argc, char *argv[]); - -/* fsverity.c */ -void usage(const struct fsverity_command *cmd, FILE *fp); -bool parse_tree_param(int opt_char, const char *arg, - struct libfsverity_merkle_tree_params *params); -void destroy_tree_params(struct libfsverity_merkle_tree_params *params); - -#endif /* PROGRAMS_FSVERITY_H */ diff --git a/programs/test_compute_digest.c b/programs/test_compute_digest.c deleted file mode 100644 index e7f2645..0000000 --- a/programs/test_compute_digest.c +++ /dev/null @@ -1,310 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Test libfsverity_compute_digest(). - * - * Copyright 2020 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "utils.h" - -#include <ctype.h> -#include <inttypes.h> - -struct mem_file { - u8 *data; - size_t size; - size_t offset; -}; - -static int read_fn(void *fd, void *buf, size_t count) -{ - struct mem_file *f = fd; - - ASSERT(count <= f->size - f->offset); - memcpy(buf, &f->data[f->offset], count); - f->offset += count; - return 0; -} - -static int error_read_fn(void *fd __attribute__((unused)), - void *buf __attribute__((unused)), - size_t count __attribute__((unused))) -{ - return -EIO; -} - -static const struct test_case { - u32 hash_algorithm; - u32 block_size; - const char *salt; - u64 file_size; - const char *digest; -} test_cases[] = { - { /* large file */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 1000000, - .block_size = 4096, - .digest = "\x48\xdf\x0c\x46\x23\x29\xcd\x87" - "\x96\x61\xbd\x05\xb3\x9a\xa8\x1b" - "\x05\xcc\x16\xaf\xd2\x7a\x71\x96" - "\xa5\x59\xda\x83\x53\x1d\x39\xd9", - }, { /* small file */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 100000, - .block_size = 4096, - .digest = "\xf2\x09\x6a\x36\xc5\xcd\xca\x4f" - "\xa3\x3e\xe8\x85\x28\x33\x15\x0b" - "\xb3\x24\x99\x2e\x54\x17\xa9\xd5" - "\x71\xf1\xbf\xff\xf7\x3b\x9e\xfc", - }, { /* single-block file */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 4096, - .block_size = 4096, - .digest = "\x6a\xc3\x99\x79\x01\x6e\x3d\xdf" - "\x3d\x39\xff\xf6\xcb\x98\x4f\x7c" - "\x11\x8a\xcd\xf1\x85\x29\x19\xf5" - "\xc1\x00\xc4\xb1\x42\xc1\x81\x8e", - }, { /* tiny file */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 1, - .block_size = 4096, - .digest = "\xb8\x03\x42\x95\x03\xd9\x59\x15" - "\x82\x9b\x29\xfd\xbc\x8b\xba\xd1" - "\x42\xf3\xab\xfd\x11\xb1\xca\xdf" - "\x55\x26\x58\x2e\x68\x5c\x05\x51", - }, { /* empty file */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 0, - .block_size = 4096, - .digest = "\x3d\x24\x8c\xa5\x42\xa2\x4f\xc6" - "\x2d\x1c\x43\xb9\x16\xea\xe5\x01" - "\x68\x78\xe2\x53\x3c\x88\x23\x84" - "\x80\xb2\x61\x28\xa1\xf1\xaf\x95", - }, { /* salt */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 1000000, - .block_size = 4096, - .salt = "abcd", - .digest = "\x91\x79\x00\xb0\xd2\x99\x45\x4a" - "\xa3\x04\xd5\xde\xbc\x6f\x39\xe4" - "\xaf\x7b\x5a\xbe\x33\xbd\xbc\x56" - "\x8d\x5d\x8f\x1e\x5c\x4d\x86\x52", - }, { /* max length salt (32 bytes) */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 1000000, - .block_size = 4096, - .salt = "0123456789:;<=>?@ABCDEFGHIJKLMNO", - .digest = "\xbc\x2d\x70\x32\x4c\x04\x8c\x22" - "\x0a\x2c\xb1\x90\x83\x21\x40\x86" - "\x3e\xb2\x68\xe6\x80\x42\x79\x39" - "\xe5\xd4\x67\xbe\xa5\xec\x5a\xd9", - }, { /* 1K block size */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 1000000, - .block_size = 1024, - .digest = "\xe9\xdf\x92\x7c\x14\xfc\xb9\x61" - "\xd5\xf5\x1c\x66\x6d\x8a\xe4\xc1" - "\x4f\xe4\xff\x98\xa3\x74\xc7\x33" - "\xe8\x98\xd0\x0c\x9e\x74\xa8\xe3", - }, { /* 512-byte block size */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 1000000, - .block_size = 512, - .digest = "\x03\x93\xee\x3d\xfd\x4a\x28\x96" - "\x6e\x2a\xf4\xe0\x7c\xfa\x5b\x03" - "\x2c\x30\xda\x5b\xb8\xe8\xef\x63" - "\xb9\xa5\x5b\xf9\x63\x26\x23\x34", - }, { /* 64K block size */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 1000000, - .block_size = 65536, - .digest = "\xf3\xb6\x41\x8f\x26\xd4\xd0\xe7" - "\x47\x28\x19\x3b\xae\x76\xf1\x5c" - "\xb4\xbb\x2c\xe9\x77\x74\x48\xd7" - "\x6b\xd8\x13\x8b\x69\xec\x61\xc2", - }, { /* SHA-512 */ - .hash_algorithm = FS_VERITY_HASH_ALG_SHA512, - .file_size = 1000000, - .block_size = 4096, - .salt = "abcd", - .digest = "\x84\x25\xc6\xd0\xc9\x4f\x84\xed" - "\x90\x4c\x12\x93\x68\x45\xfb\xb7" - "\xaf\x99\x53\x75\x37\x89\x71\x2d" - "\xcc\x3b\xe1\x42\xdb\x3d\x4b\x6b" - "\x47\xa3\x99\xad\x52\xaa\x60\x92" - "\x56\xce\x29\xa9\x60\xbf\x4b\xb0" - "\xe5\x95\xec\x38\x6c\xa5\x8c\x06" - "\x51\x9d\x54\x6d\xc5\xb1\x97\xbb", - }, { /* default hash algorithm (SHA-256) and block size (4096) */ - .file_size = 100000, - .digest = "\xf2\x09\x6a\x36\xc5\xcd\xca\x4f" - "\xa3\x3e\xe8\x85\x28\x33\x15\x0b" - "\xb3\x24\x99\x2e\x54\x17\xa9\xd5" - "\x71\xf1\xbf\xff\xf7\x3b\x9e\xfc", - }, -}; - -static void fix_digest_and_print(const struct test_case *t, - const struct libfsverity_digest *d) -{ - char alg_name[32] = {}; - size_t i; - - strncpy(alg_name, libfsverity_get_hash_name(t->hash_algorithm), - sizeof(alg_name) - 1); - for (i = 0; i < sizeof(alg_name) - 1; i++) - alg_name[i] = toupper((u8)alg_name[i]); - - printf("\t}, {\n" - "\t\t.hash_algorithm = FS_VERITY_HASH_ALG_%s,\n" - "\t\t.file_size = %" PRIu64 ",\n" - "\t\t.block_size = %u,\n", - alg_name, t->file_size, t->block_size); - if (t->salt != NULL) - printf("\t\t.salt = \"%s\",\n", t->salt); - for (i = 0; i < d->digest_size; i++) { - if (i == 0) - printf("\t\t.digest = \""); - else if (i % 8 == 0) - printf("\t\t\t \""); - printf("\\x%02x", d->digest[i]); - if (i + 1 == d->digest_size) - printf("\",\n"); - else if (i % 8 == 7) - printf("\"\n"); - } -} - -static void test_invalid_params(void) -{ - struct mem_file f = { .data = (u8 *)"abcd", .size = 4 }; - struct libfsverity_merkle_tree_params good_params = { - .version = 1, - .hash_algorithm = FS_VERITY_HASH_ALG_SHA256, - .file_size = 4, - .block_size = 4096, - }; - struct libfsverity_merkle_tree_params params; - struct libfsverity_digest *d = NULL; - - libfsverity_set_error_callback(NULL); - - ASSERT(libfsverity_compute_digest(&f, read_fn, &good_params, &d) == 0); - f.offset = 0; - free(d); - d = NULL; - - /* missing required arguments */ - ASSERT(libfsverity_compute_digest(&f, NULL, &good_params, &d) == -EINVAL); - ASSERT(libfsverity_compute_digest(&f, read_fn, NULL, &d) == -EINVAL); - ASSERT(libfsverity_compute_digest(&f, read_fn, &good_params, NULL) == -EINVAL); - - /* bad version */ - params = good_params; - params.version = 0; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - params.version = 1000; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - - /* bad hash_algorithm */ - params = good_params; - params.hash_algorithm = 1000; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - - /* bad block_size */ - params = good_params; - params.block_size = 1; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - params.block_size = 4097; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - - /* bad salt_size */ - params = good_params; - params.salt_size = 1000; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - params.salt = (u8 *)""; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - - /* bad reserved fields */ - params = good_params; - params.reserved1[0] = 1; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - params = good_params; - params.reserved1[ARRAY_SIZE(params.reserved1) - 1] = 1; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - params = good_params; - params.reserved2[0] = 1; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - params = good_params; - params.reserved2[ARRAY_SIZE(params.reserved2) - 1] = 1; - ASSERT(libfsverity_compute_digest(&f, read_fn, ¶ms, &d) == -EINVAL); - - /* error reading file */ - ASSERT(libfsverity_compute_digest(&f, error_read_fn, &good_params, &d) == -EIO); - - ASSERT(d == NULL); -} - -int main(int argc, char *argv[]) -{ - const bool update = (argc == 2 && !strcmp(argv[1], "--update")); - size_t i; - struct mem_file f = {}; - struct libfsverity_merkle_tree_params params; - struct libfsverity_digest *d; - int err; - - install_libfsverity_error_handler(); - - for (i = 0; i < ARRAY_SIZE(test_cases); i++) - f.size = max(f.size, test_cases[i].file_size); - - f.data = xmalloc(f.size); - for (i = 0; i < f.size; i++) - f.data[i] = (i % 11) + (i % 439) + (i % 1103); - - for (i = 0; i < ARRAY_SIZE(test_cases); i++) { - u32 expected_alg = test_cases[i].hash_algorithm ?: - FS_VERITY_HASH_ALG_SHA256; - - memset(¶ms, 0, sizeof(params)); - params.version = 1; - params.hash_algorithm = test_cases[i].hash_algorithm; - params.file_size = test_cases[i].file_size; - params.block_size = test_cases[i].block_size; - if (test_cases[i].salt) { - params.salt = (const u8 *)test_cases[i].salt; - params.salt_size = strlen(test_cases[i].salt); - } - - f.size = test_cases[i].file_size; - f.offset = 0; - - err = libfsverity_compute_digest(&f, read_fn, ¶ms, &d); - ASSERT(err == 0); - - ASSERT(d->digest_algorithm == expected_alg); - ASSERT(d->digest_size == - libfsverity_get_digest_size(expected_alg)); - if (update) - fix_digest_and_print(&test_cases[i], d); - else - ASSERT(!memcmp(d->digest, test_cases[i].digest, - d->digest_size)); - free(d); - d = NULL; - } - free(f.data); - if (update) { - printf("\t}\n"); - return 1; - } - - test_invalid_params(); - printf("test_compute_digest passed\n"); - return 0; -} diff --git a/programs/test_hash_algs.c b/programs/test_hash_algs.c deleted file mode 100644 index ede9f05..0000000 --- a/programs/test_hash_algs.c +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Test the hash algorithm-related libfsverity APIs. - * - * Copyright 2020 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "utils.h" - -#define SHA256_DIGEST_SIZE 32 -#define SHA512_DIGEST_SIZE 64 - -int main(void) -{ - install_libfsverity_error_handler(); - - ASSERT(libfsverity_get_digest_size(0) == -1); - ASSERT(libfsverity_get_hash_name(0) == NULL); - ASSERT(libfsverity_find_hash_alg_by_name("bad") == 0); - ASSERT(libfsverity_find_hash_alg_by_name(NULL) == 0); - - ASSERT(libfsverity_get_digest_size(100) == -1); - ASSERT(libfsverity_get_hash_name(100) == NULL); - - ASSERT(libfsverity_get_digest_size(FS_VERITY_HASH_ALG_SHA256) == - SHA256_DIGEST_SIZE); - ASSERT(!strcmp("sha256", - libfsverity_get_hash_name(FS_VERITY_HASH_ALG_SHA256))); - ASSERT(libfsverity_find_hash_alg_by_name("sha256") == - FS_VERITY_HASH_ALG_SHA256); - - ASSERT(libfsverity_get_digest_size(FS_VERITY_HASH_ALG_SHA512) == - SHA512_DIGEST_SIZE); - ASSERT(!strcmp("sha512", - libfsverity_get_hash_name(FS_VERITY_HASH_ALG_SHA512))); - ASSERT(libfsverity_find_hash_alg_by_name("sha512") == - FS_VERITY_HASH_ALG_SHA512); - - printf("test_hash_algs passed\n"); - return 0; -} diff --git a/programs/test_sign_digest.c b/programs/test_sign_digest.c deleted file mode 100644 index 412c6cb..0000000 --- a/programs/test_sign_digest.c +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -/* - * Test libfsverity_sign_digest(). - * - * Copyright 2020 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ - -#include "utils.h" - -#include <fcntl.h> - -#define SHA256_DIGEST_SIZE 32 - -int main(void) -{ - struct libfsverity_digest *d = xzalloc(sizeof(*d) + SHA256_DIGEST_SIZE); - const struct libfsverity_signature_params params = { - .keyfile = "testdata/key.pem", - .certfile = "testdata/cert.pem", - }; - u8 *sig; - size_t sig_size; - struct filedes file; - u8 *expected_sig; - u64 expected_sig_size; - int err; - - install_libfsverity_error_handler(); - - d->digest_algorithm = FS_VERITY_HASH_ALG_SHA256; - d->digest_size = SHA256_DIGEST_SIZE; - memcpy(d->digest, - "\x91\x79\x00\xb0\xd2\x99\x45\x4a\xa3\x04\xd5\xde\xbc\x6f\x39" - "\xe4\xaf\x7b\x5a\xbe\x33\xbd\xbc\x56\x8d\x5d\x8f\x1e\x5c\x4d" - "\x86\x52", SHA256_DIGEST_SIZE); - - err = libfsverity_sign_digest(d, ¶ms, &sig, &sig_size); - ASSERT(err == 0); - - ASSERT(open_file(&file, "testdata/file.sig", O_RDONLY, 0)); - ASSERT(get_file_size(&file, &expected_sig_size)); - ASSERT(sig_size == expected_sig_size); - expected_sig = xmalloc(sig_size); - ASSERT(full_read(&file, expected_sig, sig_size)); - ASSERT(!memcmp(sig, expected_sig, sig_size)); - - free(d); - free(sig); - free(expected_sig); - filedes_close(&file); - printf("test_sign_digest passed\n"); - return 0; -} diff --git a/programs/utils.h b/programs/utils.h deleted file mode 100644 index ab5005f..0000000 --- a/programs/utils.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * Utility functions for programs - * - * Copyright 2018 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. - */ -#ifndef PROGRAMS_UTILS_H -#define PROGRAMS_UTILS_H - -#include "libfsverity.h" -#include "../common/common_defs.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -void *xmalloc(size_t size); -void *xzalloc(size_t size); -void *xmemdup(const void *mem, size_t size); -char *xstrdup(const char *s); - -__printf(1, 2) __cold void error_msg(const char *format, ...); -__printf(1, 2) __cold void error_msg_errno(const char *format, ...); -__printf(1, 2) __cold __noreturn void fatal_error(const char *format, ...); -__cold __noreturn void assertion_failed(const char *expr, - const char *file, int line); - -#define ASSERT(e) ({ if (!(e)) assertion_failed(#e, __FILE__, __LINE__); }) - -void install_libfsverity_error_handler(void); - -struct filedes { - int fd; - char *name; /* filename, for logging or error messages */ -}; - -bool open_file(struct filedes *file, const char *filename, int flags, int mode); -bool get_file_size(struct filedes *file, u64 *size_ret); -bool full_read(struct filedes *file, void *buf, size_t count); -bool full_write(struct filedes *file, const void *buf, size_t count); -bool filedes_close(struct filedes *file); -int read_callback(void *file, void *buf, size_t count); - -bool hex2bin(const char *hex, u8 *bin, size_t bin_len); -void bin2hex(const u8 *bin, size_t bin_len, char *hex); - -#endif /* PROGRAMS_UTILS_H */ diff --git a/scripts/do-release.sh b/scripts/do-release.sh deleted file mode 100755 index 352fcf1..0000000 --- a/scripts/do-release.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT -# Copyright 2020 Google LLC -# -# Use of this source code is governed by an MIT-style -# license that can be found in the LICENSE file or at -# https://opensource.org/licenses/MIT. - -set -e -u -o pipefail -cd "$(dirname "$0")/.." - -if [ $# != 1 ]; then - echo "Usage: $0 VERS" 1>&2 - echo " e.g. $0 1.0" 1>&2 - exit 2 -fi - -VERS=$1 -PKG=fsverity-utils-$VERS - -git checkout -f -git clean -fdx -./scripts/run-tests.sh -git clean -fdx - -major=$(echo "$VERS" | cut -d. -f1) -minor=$(echo "$VERS" | cut -d. -f2) -sed -E -i -e "/FSVERITY_UTILS_MAJOR_VERSION/s/[0-9]+/$major/" \ - -e "/FSVERITY_UTILS_MINOR_VERSION/s/[0-9]+/$minor/" \ - include/libfsverity.h -sed -E -i "/Version:/s/[0-9]+\.[0-9]+/$VERS/" \ - lib/libfsverity.pc.in -git commit -a --signoff --message="v$VERS" -git tag --sign "v$VERS" --message="$PKG" - -git archive "v$VERS" --prefix="$PKG/" > "$PKG.tar" -tar xf "$PKG.tar" -( cd "$PKG" && make check ) -rm -r "$PKG" - -gpg --detach-sign --armor "$PKG.tar" -DESTDIR=/pub/linux/kernel/people/ebiggers/fsverity-utils/v$VERS -kup mkdir "$DESTDIR" -kup put "$PKG.tar" "$PKG.tar.asc" "$DESTDIR/$PKG.tar.gz" -git push -git push --tags diff --git a/scripts/run-sparse.sh b/scripts/run-sparse.sh deleted file mode 100755 index f75b837..0000000 --- a/scripts/run-sparse.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT -# Copyright 2020 Google LLC -# -# Use of this source code is governed by an MIT-style -# license that can be found in the LICENSE file or at -# https://opensource.org/licenses/MIT. - -set -e -u -o pipefail - -find . -name '*.c' | while read -r file; do - sparse "$file" -gcc-base-dir "$(gcc --print-file-name=)" \ - -Iinclude -D_FILE_OFFSET_BITS=64 -Wbitwise -D_GNU_SOURCE -done diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh deleted file mode 100755 index 530fe34..0000000 --- a/scripts/run-tests.sh +++ /dev/null @@ -1,187 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: MIT -# Copyright 2020 Google LLC -# -# Use of this source code is governed by an MIT-style -# license that can be found in the LICENSE file or at -# https://opensource.org/licenses/MIT. -# -# -# Test script for fsverity-utils. Runs 'make check' in lots of configurations, -# runs static analysis, and does a few other tests. -# -# Note: for more test coverage, in addition to running this script, also build -# fsverity-utils into a kvm-xfstests test appliance and run -# 'kvm-xfstests -c ext4,f2fs -g verity' - -set -e -u -o pipefail -cd "$(dirname "$0")/.." - -log() { - echo "[$(date)] $*" 1>&2 -} - -fail() { - echo "FAIL: $*" 1>&2 - exit 1 -} - -TMPDIR=$(mktemp -d -t libfsverity_test.XXXXXXXXX) -trap 'rm -r "$TMPDIR"' EXIT - -# Both stdout and stderr go to log file. -# Only stderr goes to terminal. -echo "Starting fsverity-utils tests. See run-tests.log for full output." -rm -f run-tests.log -exec >> run-tests.log -exec 2> >(tee -ia run-tests.log 1>&2) - -MAKE="make -j$(getconf _NPROCESSORS_ONLN)" - -log "Build and test with statically linking" -$MAKE CFLAGS="-Werror" -if ldd fsverity | grep libfsverity.so; then - fail "fsverity binary should be statically linked to libfsverity by default" -fi -./fsverity --version - -log "Check that all global symbols are prefixed with \"libfsverity_\"" -if nm libfsverity.a | grep ' T ' | grep -v " libfsverity_"; then - fail "Some global symbols are not prefixed with \"libfsverity_\"" -fi - -log "Build and test with dynamic linking" -$MAKE CFLAGS="-Werror" USE_SHARED_LIB=1 check -if ! ldd fsverity | grep libfsverity.so; then - fail "fsverity binary should be dynamically linked to libfsverity when USE_SHARED_LIB=1" -fi - -log "Check that all exported symbols are prefixed with \"libfsverity_\"" -if nm libfsverity.so | grep ' T ' | grep -v " libfsverity_"; then - fail "Some exported symbols are not prefixed with \"libfsverity_\"" -fi - -log "Test using libfsverity from C++ program" -cat > "$TMPDIR/test.cc" <<EOF -#include <libfsverity.h> -#include <iostream> -int main() -{ - std::cout << libfsverity_get_digest_size(FS_VERITY_HASH_ALG_SHA256) << std::endl; -} -EOF -c++ -Wall -Werror "$TMPDIR/test.cc" -Iinclude -L. -lfsverity -o "$TMPDIR/test" -[ "$(LD_LIBRARY_PATH=. "$TMPDIR/test")" = "32" ] -rm "${TMPDIR:?}"/* - -log "Check that build doesn't produce untracked files" -$MAKE CFLAGS="-Werror" all test_programs -if git status --short | grep -q '^??'; then - git status - fail "Build produced untracked files (check 'git status'). Missing gitignore entry?" -fi - -log "Test that 'make uninstall' uninstalls all files" -make DESTDIR="$TMPDIR" install -if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" = 0 ]; then - fail "'make install' didn't install any files" -fi -make DESTDIR="$TMPDIR" uninstall -if [ "$(find "$TMPDIR" -type f -o -type l | wc -l)" != 0 ]; then - fail "'make uninstall' didn't uninstall all files" -fi -rm -r "${TMPDIR:?}"/* - -log "Build, install, and uninstall with dash" -make clean SHELL=/bin/dash -make DESTDIR="$TMPDIR" SHELL=/bin/dash install -make DESTDIR="$TMPDIR" SHELL=/bin/dash uninstall - -log "Check that all files have license and copyright info" -list="$TMPDIR/filelist" -filter_license_info() { - # files to exclude from license and copyright info checks - grep -E -v '(\.gitignore|LICENSE|NEWS|README|testdata|fsverity_uapi\.h|libfsverity\.pc\.in)' -} -git grep -L 'SPDX-License-Identifier: MIT' \ - | filter_license_info > "$list" || true -if [ -s "$list" ]; then - fail "The following files are missing an appropriate SPDX license identifier: $(<"$list")" -fi -# For now some people still prefer a free-form license statement, not just SPDX. -git grep -L 'Use of this source code is governed by an MIT-style' \ - | filter_license_info > "$list" || true -if [ -s "$list" ]; then - fail "The following files are missing an appropriate license statement: $(<"$list")" -fi -git grep -L '\<Copyright\>' | filter_license_info > "$list" || true -if [ -s "$list" ]; then - fail "The following files are missing a copyright statement: $(<"$list")" -fi -rm "$list" - -log "Build and test with gcc (-O2)" -$MAKE CC=gcc CFLAGS="-O2 -Werror" check - -log "Build and test with gcc (-O3)" -$MAKE CC=gcc CFLAGS="-O3 -Werror" check - -log "Build and test with gcc (32-bit)" -$MAKE CC=gcc CFLAGS="-O2 -Werror -m32" check - -log "Build and test with clang (-O2)" -$MAKE CC=clang CFLAGS="-O2 -Werror" check - -log "Build and test with clang (-O3)" -$MAKE CC=clang CFLAGS="-O3 -Werror" check - -log "Build and test with clang + UBSAN" -$MAKE CC=clang \ - CFLAGS="-O2 -Werror -fsanitize=undefined -fno-sanitize-recover=undefined" \ - check - -log "Build and test with clang + ASAN" -$MAKE CC=clang \ - CFLAGS="-O2 -Werror -fsanitize=address -fno-sanitize-recover=address" \ - check - -log "Build and test with clang + unsigned integer overflow sanitizer" -$MAKE CC=clang \ - CFLAGS="-O2 -Werror -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow" \ - check - -log "Build and test with clang + CFI" -$MAKE CC=clang CFLAGS="-O2 -Werror -fsanitize=cfi -flto -fvisibility=hidden" \ - check - -log "Build and test with valgrind" -$MAKE TEST_WRAPPER_PROG="valgrind --quiet --error-exitcode=100 --leak-check=full --errors-for-leak-kinds=all" \ - CFLAGS="-O2 -Werror" check - -log "Build and test using BoringSSL instead of OpenSSL" -BSSL=$HOME/src/boringssl -$MAKE CFLAGS="-O2 -Werror" LDFLAGS="-L$BSSL/build/crypto" \ - CPPFLAGS="-I$BSSL/include" LDLIBS="-lcrypto -lpthread" check - -log "Build and test using -funsigned-char" -$MAKE CFLAGS="-O2 -Werror -funsigned-char" check - -log "Build and test using -fsigned-char" -$MAKE CFLAGS="-O2 -Werror -fsigned-char" check - -log "Cross-compile for Windows (32-bit)" -$MAKE CC=i686-w64-mingw32-gcc CFLAGS="-O2 -Werror" - -log "Cross-compile for Windows (64-bit)" -$MAKE CC=x86_64-w64-mingw32-gcc CFLAGS="-O2 -Werror" - -log "Run sparse" -./scripts/run-sparse.sh - -log "Run clang static analyzer" -scan-build --status-bugs make CFLAGS="-O2 -Werror" all test_programs - -log "Run shellcheck" -shellcheck scripts/*.sh 1>&2 - -log "All tests passed!" diff --git a/testdata/cert.pem b/testdata/cert.pem deleted file mode 100644 index c63b965..0000000 --- a/testdata/cert.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIUYaRYcyZGDIv9fIxx/RoJwQu23+owDQYJKoZIhvcNAQEL -BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMDA1MTUwMjUyMzFaFw0yMDA2 -MTQwMjUyMzFaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQC5lXk9otBz/VM/tbvBBK6sK//HE+q3ctY4+fPVv3Ob -D1YNYuWRD59U+7K8fVUfZlXyjgxt3n4VPzkLgRSr/w5YUTa5NEOVJIltKT4ugswL -5oY8eRVSuIr1O+vTbu+EpUk3DhTaFkalVzwspwipBeiVTDO9kh0NAueRk2HyLJte -IoPyfzSCKxg9sED6/WtLFqrhDb5+1qeGoMNGM66ueWXKX0QjomMEODGXC04ypIY3 -sTwB+sYhZUe3YRpY0HyaVNh/6cxCxSiKr2jkC5UL+ry+46EJerNZbKmeqqyqmhXh -P2cHv8MO91zdH1xbXUUenLcdpK/0oq+/sTAVV1/qPvnAofpN8tdZdrH65JD753jt -s+lH/f0iGuKAb9ZpLOTM2d3wjY13OcHElj0zu2Usw9PXQpTK/DYlbcapOI4NTVyU -NpK3yP4i5dPnkHoxpjLWz75Eq6gP9ZXohGq3YG0LxtvELWfaFmpzEUTlD59hJJOZ -ELGxAXzsxLbelX/EmpX+GIqnFBpdMIuPO4HEfJwD5IcdeHqGl2iH9LIqsY5DcGj4 -hnqYplIYYk5mWgbhkexRbJIGNdn8WyXlraVp2MoSr3p7xJbmo0qYRRtt3kQShzDG -0FrZX7wqxemc/g/hr+g2xqMQj0nYLehDeodqxA2n9grDUr4AdgQyxXDMUkGZdrg3 -cwIDAQABo1MwUTAdBgNVHQ4EFgQUxpaj6YjgLFyh9UVM71hf18cb/hkwHwYDVR0j -BBgwFoAUxpaj6YjgLFyh9UVM71hf18cb/hkwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQsFAAOCAgEAQnXMCgI+eSjK+l3nrpE+TRrXZhHeB0aT3gilVtBqFM95 -GxkLzOgJnW4SU+BCKTiGjwhCEXQiFj6UNDrI7vaNzmurI370uqmC9/pwKn4/L27V -ToqLHk5d8kmvjSJyfgY/9H73srzHjNcqLG3uy+JP3/fIzaUzy7x9OUJtzdH19zic -b61kCbqe6TJrlpL0Y50FY91QTzupsIS9IsAAeYXrJiEwpkXv/O9c51swtGZmQhVD -TDn4B2aKOHecR+gKZQbPcuwTCbNLDRRPT4q0IM9yKjUxIM8vkAaxlrW3O7fgqUV0 -GU3/i0zZugq2XEludF3VelrqMUhSMqaREAtRUe3ufipwEsovDa43Hr9P6bINAfU3 -92Kv6adgeKZc4DmuEg6sFje/ET85teioHtwmjviJu6vnkbZg7x+IU01Y6YHboz/z -hTAjz9g6owgdsbTG9nptvgJllY83zBtnAGOqhJLNVZ+TC3pbbKht/7sT+s+WP2+K -81oZ3gmxIr6myMVyR5CCt+FNJ1hFxYNBJDao35iiZLxDe2s5nMJKHYezUY60ujqT -Ljv3Ku4uAk5PgXltZnWGz152ntjopA0gbnlU4f+SgnmPoBFcvn36BcUQWQbTDqmh -h+Y0OaXR3x/27M/qkPBov4IAfoCkWeF7i02wxwtdTLiSF7OjTDkQXtZemUzN5+w= ------END CERTIFICATE----- diff --git a/testdata/file.sig b/testdata/file.sig Binary files differdeleted file mode 100644 index 1ba61f8..0000000 --- a/testdata/file.sig +++ /dev/null diff --git a/testdata/key.pem b/testdata/key.pem deleted file mode 100644 index e76db4c..0000000 --- a/testdata/key.pem +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC5lXk9otBz/VM/ -tbvBBK6sK//HE+q3ctY4+fPVv3ObD1YNYuWRD59U+7K8fVUfZlXyjgxt3n4VPzkL -gRSr/w5YUTa5NEOVJIltKT4ugswL5oY8eRVSuIr1O+vTbu+EpUk3DhTaFkalVzws -pwipBeiVTDO9kh0NAueRk2HyLJteIoPyfzSCKxg9sED6/WtLFqrhDb5+1qeGoMNG -M66ueWXKX0QjomMEODGXC04ypIY3sTwB+sYhZUe3YRpY0HyaVNh/6cxCxSiKr2jk -C5UL+ry+46EJerNZbKmeqqyqmhXhP2cHv8MO91zdH1xbXUUenLcdpK/0oq+/sTAV -V1/qPvnAofpN8tdZdrH65JD753jts+lH/f0iGuKAb9ZpLOTM2d3wjY13OcHElj0z -u2Usw9PXQpTK/DYlbcapOI4NTVyUNpK3yP4i5dPnkHoxpjLWz75Eq6gP9ZXohGq3 -YG0LxtvELWfaFmpzEUTlD59hJJOZELGxAXzsxLbelX/EmpX+GIqnFBpdMIuPO4HE -fJwD5IcdeHqGl2iH9LIqsY5DcGj4hnqYplIYYk5mWgbhkexRbJIGNdn8WyXlraVp -2MoSr3p7xJbmo0qYRRtt3kQShzDG0FrZX7wqxemc/g/hr+g2xqMQj0nYLehDeodq -xA2n9grDUr4AdgQyxXDMUkGZdrg3cwIDAQABAoICACla0aWWfnUaYk60JJ6ieHoN -Y/XszkUK5gnUSS28d/p5tGdPPnDQ1mSNogq2sx1IJKbkWIizJ818RS33GbAqKfws -PNGQf+7gMW+N3TloFCgiuo8HPGUukmiLbcWz1tPsMSB/ls3yYNO/WL1qi1d+5ZE/ -Zdg8kxSvLQMXoJ/iqMyVTGnhRsYq7D/y4sgLaLlW18VG1shU9QffEyS1p5thmfk6 -uWhna0EpdIOAFXDbkL0gVYrrYvNWKmEG1mQsMVgCyCvY4ZePb7VX2TvYCOKegSjY -eK4wFX8746Bj0A5EP9Pt2Pu1E7ZmEN+FeYMyiZCEw5lrdXpCNn+08E4RJmKAng6Z -LXu7FeBwOffsEcYDk1IPtT4JAkpEO0ennjyY2X+bWu6faaSGqoTDRm0igL/2qeDK -xJCCOTPDePSDKkVFaimBncQlz4SSVS7WhqqofFMBIPBtZ6oe0c+0ZeKoaH2ZX7jU -q2DTsRbUKeRerjOlAg5WxQoLxTmLl4t7aHjm4HVafEZHqja5szyNLy13qJZyo7+x -R8kDRkVdui7XKdC9ajCMAsVcen4NyrvNqQHSoocgqmSuD3d5S/eZnE0cSGGX3Nae -pb0bAFthQdPq2qfZDDL/cRpe+0FAsOtXG66yEcQjZdsdNerU+pSi/sgArJkNj/U1 -Dqd0LCPOOFiLa/f9LO6hAoIBAQD2HHn2Ghl7W1j4t806i6tfDNocgUCaO+2wjaOY -cNrg0WiJP24oaRmXew1Le0q5NhX8wHgGZAvVOh0rkcX+sUBoSURzWFK5cavxIGmL -XqW5wHFS9ahS3mQ3I0zEbueYPyFKEg2a2aFqqq8g3XRqgZtc4kfg4GUbIoltey4z -uQlp3tIpbRjD9w2cYF9bU9xEgdp7PU5TDmYDiRetSd0HxwD2osj40sWsEbV9UN+4 -xIh6mUwn1ZcJmt7NzuHwyXGs63EhSQoxQwS/vAt0pIKwAlyn06//GBFZGhpnpjCT -flN9vQPaqJZA93kugsBEt3fX+oGbFTVHgEYsyMTEzH2by6c1AoIBAQDBCmg0ziga -2WZJE0YARf/gek3MKZNG6qjahuRynpGdtgqa6cSgnRzntDCEkLhU6KZ5+SYJNp0x -9EBkO7o8YOGWfGUtnccqdbSCt14959Vqn+kcrKnadjFiSVOAGc1728YUjd3jYGS8 -ZXkGe3xXhmXiB1mv8ekKrGY2mmx7mBiZ40gNGJNg1gboenffMeP5l7JjaO7ew5QY -A3swJkBHNIyGCdntlmrlw1vxT7bmDQoHVLKdQ+VFJFvUVyY40nVkeH1/9WB215Lu -hzDTzn5Q+Z19pjEouohsJDY6k2FbOyaT0c/KI1NDlNZmUpWcoqf7IIusg1eCCGCH -nXafifGxv7EHAoIBAAehemaXCJM6kdekW0ila/rWeyzHFSmzEfuXaKshVKgD1inr -PY8jMxfvSMo+WGLFuojLru0DzRofYygmrOzosgaJvwWUh3wYeixPxPX9SUYpIVph -I4buPk03Wvn8NlISIwYY6TMT7F1STXvHYgSrYBXRLklaq8fbmkc6uoQACLqvnfSK -3Wm2D0X59vrt7rZxEEUh8XvBxof1iDZnQ+Mp2G3NPk34uwhKxEXObCFedpzWg/X4 -OWai1qWq9HZyyIOECU3u5dIBMfR/8Br9vs+WQykw9xQBuwf4NzlffcIU+KG9apEt -CPuasLcwdqWqypx3t+0HC0/cOlDJKNCxRnO+LMECggEABzLoJ+/4NugclGUPmzsB -C9IDzLVQNLjTizK0mkGnlIYRZy2Ik6TISyvBE3CCL0htzOapsHZE7nP5YsOHcnD6 -eK4y57yWjNLO5IEKFqzqnItSGiumOetmdA/f+Ur9Cr1raaDQwYX6u7vdA4zfWjQ8 -4Gz9vz36PtenCCpCGWnWoQaEzVg5Rsc0gr7ucXhe1BQAJwzmu4/3md2nXmhOxVkE -VItRgTa2zdK3PwyF+ZZK5XMXJh4+EpIEiqqlVkEi95g2terkqgnoBNUt0PhGZaap -ZOIpuycZp07CZvTQEKLoEWMlqJggpsiKJk62HZ1DPm48RzausL63Otd4cQKn7MUF -SQKCAQAHbuzSCvI1YUnFiXtfNLIXdfTV1UJ+y9Mmb3/Lz/wvfbGiAC+TrJ4sdA7R -k4riwnrv3F3kMop1gxQk1iWSt6qPg2tvw6ZoBcnzE6qJ2/xSdIXgrpV4kCrxAVYz -vYt9KMWp17mgk4BYbnYU/1U1hZVowlhyx+lzsZtaRRnySvxeEcCO+eR6jTKAXWfH -rVlbGuuBcTQ/Sz+Jw7mIM3gcI+fE9FyRznSjgVnsXqIsV9bntqkEUFb8VfunR2g5 -6eMoP8XSQdTcEvtKNJ2hrr9fkRABE4L/EeaMT4XOcYyNN9nPka+uj2nRoB9Vsb25 -x55d2r87sh6ScDvl57EIav09Y6W/ ------END PRIVATE KEY----- diff --git a/programs/utils.c b/util.c index ce19b57..2218f2e 100644 --- a/programs/utils.c +++ b/util.c @@ -1,23 +1,24 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: GPL-2.0+ /* * Utility functions for the 'fsverity' program * - * Copyright 2018 Google LLC + * Copyright (C) 2018 Google LLC * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. + * Written by Eric Biggers. */ -#include "utils.h" - #include <errno.h> #include <fcntl.h> #include <limits.h> #include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include <unistd.h> +#include "util.h" + /* ========== Memory allocation ========== */ void *xmalloc(size_t size) @@ -46,7 +47,7 @@ char *xstrdup(const char *s) /* ========== Error messages and assertions ========== */ -static void do_error_msg(const char *format, va_list va, int err) +void do_error_msg(const char *format, va_list va, int err) { fputs("ERROR: ", stderr); vfprintf(stderr, format, va); @@ -88,21 +89,11 @@ __noreturn void assertion_failed(const char *expr, const char *file, int line) fatal_error("Assertion failed: %s at %s:%d", expr, file, line); } -static void print_libfsverity_error(const char *msg) -{ - error_msg("%s", msg); -} - -void install_libfsverity_error_handler(void) -{ - libfsverity_set_error_callback(print_libfsverity_error); -} - /* ========== File utilities ========== */ bool open_file(struct filedes *file, const char *filename, int flags, int mode) { - file->fd = open(filename, flags | O_BINARY, mode); + file->fd = open(filename, flags, mode); if (file->fd < 0) { error_msg_errno("can't open '%s' for %s", filename, (flags & O_ACCMODE) == O_RDONLY ? "reading" : @@ -175,14 +166,6 @@ bool filedes_close(struct filedes *file) return res == 0; } -int read_callback(void *file, void *buf, size_t count) -{ - errno = 0; - if (!full_read(file, buf, count)) - return errno ? -errno : -EIO; - return 0; -} - /* ========== String utilities ========== */ static int hex2bin_char(char c) @@ -198,18 +181,16 @@ static int hex2bin_char(char c) bool hex2bin(const char *hex, u8 *bin, size_t bin_len) { - size_t i; - if (strlen(hex) != 2 * bin_len) return false; - for (i = 0; i < bin_len; i++) { + while (bin_len--) { int hi = hex2bin_char(*hex++); int lo = hex2bin_char(*hex++); if (hi < 0 || lo < 0) return false; - bin[i] = (hi << 4) | lo; + *bin++ = (hi << 4) | lo; } return true; } @@ -225,11 +206,10 @@ static char bin2hex_char(u8 nibble) void bin2hex(const u8 *bin, size_t bin_len, char *hex) { - size_t i; - - for (i = 0; i < bin_len; i++) { - *hex++ = bin2hex_char(bin[i] >> 4); - *hex++ = bin2hex_char(bin[i] & 0xf); + while (bin_len--) { + *hex++ = bin2hex_char(*bin >> 4); + *hex++ = bin2hex_char(*bin & 0xf); + bin++; } *hex = '\0'; } diff --git a/common/common_defs.h b/util.h index 3ae5561..dfa10f2 100644 --- a/common/common_defs.h +++ b/util.h @@ -1,21 +1,16 @@ -/* SPDX-License-Identifier: MIT */ +/* SPDX-License-Identifier: GPL-2.0+ */ /* - * Common definitions for libfsverity and the 'fsverity' program + * Utility functions and macros for the 'fsverity' program * - * Copyright 2018 Google LLC - * - * Use of this source code is governed by an MIT-style - * license that can be found in the LICENSE file or at - * https://opensource.org/licenses/MIT. + * Copyright (C) 2018 Google LLC */ -#ifndef COMMON_COMMON_DEFS_H -#define COMMON_COMMON_DEFS_H +#ifndef UTIL_H +#define UTIL_H +#include <inttypes.h> +#include <stdarg.h> #include <stdbool.h> #include <stddef.h> -#include <stdint.h> - -#include "win32_defs.h" typedef uint8_t u8; typedef uint16_t u16; @@ -48,7 +43,6 @@ typedef uint64_t u64; __typeof__(b) _b = (b); \ _a < _b ? _a : _b; \ }) - #define max(a, b) ({ \ __typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ @@ -92,4 +86,40 @@ static inline int ilog2(unsigned long n) # define le64_to_cpu(v) (__builtin_bswap64((__force u64)(v))) #endif -#endif /* COMMON_COMMON_DEFS_H */ +/* ========== Memory allocation ========== */ + +void *xmalloc(size_t size); +void *xzalloc(size_t size); +void *xmemdup(const void *mem, size_t size); +char *xstrdup(const char *s); + +/* ========== Error messages and assertions ========== */ + +__cold void do_error_msg(const char *format, va_list va, int err); +__printf(1, 2) __cold void error_msg(const char *format, ...); +__printf(1, 2) __cold void error_msg_errno(const char *format, ...); +__printf(1, 2) __cold __noreturn void fatal_error(const char *format, ...); +__cold __noreturn void assertion_failed(const char *expr, + const char *file, int line); + +#define ASSERT(e) ({ if (!(e)) assertion_failed(#e, __FILE__, __LINE__); }) + +/* ========== File utilities ========== */ + +struct filedes { + int fd; + char *name; /* filename, for logging or error messages */ +}; + +bool open_file(struct filedes *file, const char *filename, int flags, int mode); +bool get_file_size(struct filedes *file, u64 *size_ret); +bool full_read(struct filedes *file, void *buf, size_t count); +bool full_write(struct filedes *file, const void *buf, size_t count); +bool filedes_close(struct filedes *file); + +/* ========== String utilities ========== */ + +bool hex2bin(const char *hex, u8 *bin, size_t bin_len); +void bin2hex(const u8 *bin, size_t bin_len, char *hex); + +#endif /* UTIL_H */ |