74 Commits
v0.3 ... v0.8

Author SHA1 Message Date
7ece92b4e1 Release version 0.8
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-05-05 10:01:26 +03:00
dde9e21a4a Fix parameter name in help output
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-05-02 18:51:15 +03:00
6ec61ab9cb Remove unused 'x' parameter
'-x' option was removed a while ago, but 'x' was not removed
from getopt_long() parameter. Remove it.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-05-02 18:43:45 +03:00
77986c80ac Add Mimi to AUTHORS list
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-05-02 17:49:42 +03:00
2b893135be Update license text with OpenSSL exception clause
Ubuntu/Debian requires to provide OpenSSL exception clause.
This patch fixes it.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-05-02 17:19:47 +03:00
8feba3f462 Add support for signing a file hash
In a number of situations, the file hash has already been calculated.
Instead of reading a file to calculate the file hash, read the file hash
from stdin; and instead of writing the signature as an xattr or creating
a .sig file, output the signature as ascii-hex to stdout.

For example, piping the output of sha256sum <pathname> to evmctl would
display the original sha256 output with the file signature appended.

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2014-03-26 14:50:20 +02:00
b0da7e69e0 Define symbolic keyring name
Currently evmctl supports importing keys onto a particular keyring
based on a numeric keyring identifier.  This patch adds support
for importing keys based special values as defined by keyctl.

   Thread keyring: @t (-1)
   Process keyring: @p (-2)
   Session keyring: @s (-3)
   User specific keyring: @u (-4)
   User default session keyring: @us (-5)
   Group specific keyring: @g (-6)

Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
2014-03-05 13:03:36 +02:00
bed3cc06f1 Release new version v0.7
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 16:29:20 +02:00
bddbd31a15 Provide random KMK example instead of fixed testing123
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 16:21:52 +02:00
c7042472e8 Limit includes in imaevm.h
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 15:56:07 +02:00
12af148131 Rename library, header file and export it.
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 15:56:07 +02:00
ca6b42ab17 Use --m32 and --m64 parameters also in HMAC signing code
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 15:56:07 +02:00
5e8564d155 Provide target architecture size parameter
'--m32|--m64' parameter can be specified to label images for different
architecture size than host.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 15:56:07 +02:00
f3cef2c047 Provide additional debug info for hmac_misc
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 15:56:07 +02:00
ef46876b10 Include only libraries to the package
Prevent including debug stuff to the main package.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-02-17 15:56:07 +02:00
5f30ed1da6 Remove experimental module signing functionality
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 16:04:47 +02:00
86a605eb10 Remove verify_hash parameter
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 15:59:24 +02:00
fd7e949c29 Remove x509 library parameter
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 15:37:54 +02:00
e92cbe4756 Remove user_hash_algo
Use always hash algo from signature like kernel does.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 15:27:49 +02:00
86d8772653 Use EVM v2 HMAC format by default
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 15:25:05 +02:00
317fa60467 Do use x509 by default
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 15:20:54 +02:00
f9a3d7c378 Select signing function in single place
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 15:01:17 +02:00
454350d294 Select verification function version in the library code
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 14:57:16 +02:00
4578679081 Remove user_sig_type flag
Always use signature type from signature header - like kernel does.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 14:54:59 +02:00
ff5f07e171 Use verify_hash() for EVM verification as well
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 14:50:09 +02:00
3299fba40d Move signature version checking to verify_hash()
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 14:48:02 +02:00
906861a308 Move hash verification to separate function
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 14:42:22 +02:00
6aabda5b65 Move signature verification implementation to the library
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-24 13:59:18 +02:00
018495c87f Initial library skeleton
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 18:43:44 +02:00
3dc656bc6f Implement recursive IMA signing
Recursive signing is needed when doing filesystem image signing.
Using script is very slow due to multiple forking and executing.
C-based implementation provides about 7 times performance improvements.
It is very significant when doing large image signing.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 15:27:20 +02:00
5b852c0fbb Rename de_type to search_type
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 15:27:20 +02:00
e4e0cabc21 Move file type checking to separate function
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 15:27:20 +02:00
51dbb77c4f Implement recursive EVM signing
Recursive signing is needed when doing filesystem image signing.
Using script is very slow due to multiple forking and executing.
C-based implementation provides about 7 times performance improvements.
It is very significant when doing large image signing.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 15:27:12 +02:00
eda8a164e0 Export find() declaration for the following patches
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 14:56:19 +02:00
6c0ebe2be6 Prevent reading of inode generation for special files in HMAC signing
Kernel API does not support at the momement reading of inode generation
number of special files, so do not do it also when do HMAC signing.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 14:56:19 +02:00
fd08fdeeb5 Prevent reading of inode generation for special files
Kernel API does not support at the momement reading of
generation number of special files, so do not do it.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 14:56:19 +02:00
05017f3e98 Use lgetxattr() instead of getxattr()
IMA/EVM extended attributes should be get for symbolic links themselves,
not to the entries pointed by them. setxattr() dereference symbolic links.
It is necessary to use lgetxattr().

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 14:56:19 +02:00
33ff9595e5 Use lsetxattr() instead of setxattr()
IMA/EVM extended attributes should be set for symbolic links themselves,
not to the entries pointed by them. setxattr() dereference symbolic links.
It is necessary to use lsetxattr().

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 12:47:47 +02:00
7045d70a1e Implement recursive efficient IMA fixing
Using scripts which do many forking and execution is very slow on
embedded/mobile devices. C based implementation is about 7 times faster.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-17 12:43:03 +02:00
323d81777d Script for generating self-signed certificate
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-16 13:36:18 +02:00
73f10810c0 Provide spec file for gbs build system
GBS build system requires specfile before configuring the package.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-16 13:35:22 +02:00
504e1d4013 Move spec file to packaging directory
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-16 13:34:48 +02:00
08043fc800 IMA measurement list verification (experimental)
PCR aggregate value is reconstructed using IMA measurement list and is compared
against TPM PCR-10. It also performs signature verification if it is available in
the measurement list. ima_measurement_new.c (Mimi Zohar) was used as an example.

Example:
  evmctl ima_measurement /sys/kernel/security/ima/binary_runtime_measurements

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2014-01-15 18:19:35 +02:00
afcef2b493 Define __packed
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-11-12 19:27:36 +02:00
20f1837d51 Provide hexdump functions without new line
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-11-12 19:20:58 +02:00
6918bfbf20 split signature verification function for passing signature as an argument
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-11-12 18:35:16 +02:00
092d5cc15d scripts to generate ca and keys
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-11-01 01:30:40 +02:00
78ccd56afe License changed from LGPL to GPL as in COPYING
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-09-04 16:51:44 +03:00
f1ba3e7b45 Version 0.6 release
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-08-28 16:37:52 +03:00
d7d74e5648 Fix cleanup in the case of errors
Proper memory cleanup is not really necessary for command line
utility because all memory is cleaned up when it quits. But as
code does it most of the cases, fix other places.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-08-28 15:20:16 +03:00
15dab873b5 fix the crash when key file is not found
Error in error handling caused crash when key file is not found.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-08-27 15:44:18 +03:00
971b286169 make --imahash or --imasig optional for EVM signing
One might not want to change/set IMA xattr value when performing
EVM signing.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-08-13 16:55:14 +03:00
2406322914 perform uuid format checking and error handling
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-08-13 16:55:14 +03:00
b3a5fcbca2 make argument for '-u' option as optional
-u required to provide uuid or '-', which was confusing.
Now -u does not require '-' argument to read uuid automatically.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-08-13 16:55:10 +03:00
59ef0a0b99 Save full security.ima attribute to a file
Right now if -f option is passed in, we only save the actual signature to
a file and not the full security.ima attribute.

I think it makes more sense to save full security.ima attribute so that
it can act as detached signatures and one can install signature later.
That is signing can take place on build server and detached signatures
can be generated and these signatures can be installed later on target.

One can use following steps.

evmctl ima_sign -f -x -a sha256 /tmp/data.txt

hexdump -v -e '1/1 "%02x"' /tmp/data.txt.sig > /tmp/data.txt.sig.hex
printf "# file: /tmp/data.txt\nsecurity.ima=0x" | cat - /tmp/data.txt.sig.hex | setfattr --restore -

evmctl ima_verify /tmp/data.txt

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-08-09 15:57:26 +03:00
ab18c60ec1 Get signature version from the header
Currently we assume signature version is v1 until and unless -x is
specified on kernel command line. Given the fact that signature version
information is available in signature itself, it is much better to get
it from there and not require user to pass -x during verification phase.

If user passed -x on command line, then honor it.

Now one can do following.

	evmctl ima_sign -x /tmp/data.txt
	evmctl ima_verify /tmp/data.txt

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-08-09 15:57:26 +03:00
d9678295b9 Move key file selection to later phase
Following patch reads signature version from header and based
on that key file needs to be selected.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-08-09 15:57:18 +03:00
0df73005a3 Use enums for signature versions
Using enums for fixed values looks cleaner. Also I am planning to use
version field in more places in next patch. So use enums intead of
numbers like 1 and 2.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-08-09 15:55:53 +03:00
b49e2251a0 Let user specified hash algo take precedence
After applying previous patch, we will always get hash algo info from
signature and if user specified one on command line, that will be overridden.

This is like breaking old behavior. So keep track whether user specified
hash algo on command line or not. If user did not specify one then get
hash algo info from signature otherwise use the one user provided.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-08-09 15:55:49 +03:00
fa3c365cce Get hash algorithm info from the signature
If one signs a file using hash algo -sha256 then one needs to specify
signature during verification also. Otherwise evmctl using default sha1
for calculating hash and signature verification fails. One needs to
specify -a sha256 on command line even during signature verification
phase to make sure file is signed right.

I think that's completely unnecessary. A user is not always supposed
to know what algorithm was used to generate signature. User is only
concered with whether this signature is valid or not.

So retrieve hash algorithm info from signature and use that.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-07-15 18:02:02 +03:00
00caa1d5ba Put right hash algo info in digital signature version 1 header
hdr->hash for signature version 1 contains the info about what hash
algorithm has been used for signing the file. Currently we always set
hdr->hash to DIGEST_ALGO_SHA1. But one can sign file using SHA256 using
option "-a sha256". In that case we should put right hash algo info
in signature header. Fix it.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-07-15 18:01:05 +03:00
b48f4f9c7e Fix hash array size in verify_ima()
Now evmctl supports different hash algorithms and sha512 will produce
64 byte digest. verify_ima() still allocates only 20bytes to store hash.
This does not work with larger hashes.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-07-15 18:00:32 +03:00
16d40dbdf6 evmctl: Fix signature verification code for V2 digital signature
For V2 of digital signature we store signature at hdr->sig and not at
hdr->sig + 2. That's the property of V1 of signature.

Fix the verification code otherwise it fails with following message.

RSA_public_decrypt() failed: -1
error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01
error:04067072:rsa routines:RSA_EAY_PUBLIC_DECRYPT:padding check failed

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
2013-07-10 16:45:38 +01:00
3f0c0a3c84 Fix verification using signature file
Signature file does not contain xattr prefix.
Add signature xattr prefix manually.

Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
2013-07-10 16:00:53 +01:00
076fd302bb support for asymmetric crypto keys and new signature format
Asymmetric keys were introduced in linux-3.7 to verify the signature on
signed kernel modules. The asymmetric keys infrastructure abstracts the
signature verification from the crypto details. Asymmetric crypto keys
support allows to import X509 public key certificate in a DER format
into the kernel keyring. Asymmetric keys require a new signature format.
'evmctl -x' or 'evmctl --x509' option can be used to utilize new
signature format.

Using of key filename after the file name for signing and verification commands
is a bit odd. This patch add '--key' parameter to specify non-default key file.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2013-02-11 16:12:08 +02:00
1d24a94bb5 added uuid support for EVM
Latest version of EVM uses file system UUID as part of an HMAC
calculation to prevent pasting of inode metadata from other file
systems. This patch adds support for adding file system UUID
to HMAC calculation. It is necessary to specify '-u -' or '--uuid -'
on evmctl command line.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2013-02-11 16:07:30 +02:00
5be54eaca4 Update README
README updated.
Module signing info has been removed. Module signing is done now in kernel
source tree and uses appended signatures. No need to create sig files or
set extended attributes. Information about test scripts has been removed.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-10 15:37:40 +03:00
a58cd9f4af Remove test scripts
Test scripts are not used at all.
All needed information is in README.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-10 15:17:42 +03:00
c8b4f34fd4 remove directory entry list sorting
Directory entries list sorting is not needed.
Entries are read always in the same order.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
c171931236 added ima signature verification support
For debugging puporse it is usefull to have signature verification
functionality. It supports use of xattrs and .sig files.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
ba07c9d4b1 do not output type prefix for sig files
sig files do not need type prefix as they are contain only signatures.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
203f058903 added support for kernel module signature
Kernel module signature is appended to the kernel module.
Kernel signature also contains signature length and magic.
Added --modsig parameter to generate kernel module signature.

Signature can be added to the module like: cat module.sig >> module.ko

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
72ad26c3be disable printing signature when using sigfiles
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
f41d43026b Remove tag creation
Better to create tag manually when release is done.

Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
2012-09-06 14:08:54 +03:00
25 changed files with 2139 additions and 770 deletions

View File

@ -1,2 +1,6 @@
Dmitry Kasatkin <dmitry.kasatkin@intel.com>
Dmitry Kasatkin <d.kasatkin@samsung.com>
CONTRIBUTORS:
Vivek Goyal <vgoyal@redhat.com>
Mimi Zohar <zohar@linux.vnet.ibm.com>

41
COPYING
View File

@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@ -15,7 +15,7 @@ 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 Library General Public License instead.) You can apply it to
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
@ -55,8 +55,8 @@ 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
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
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
@ -168,7 +168,7 @@ 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
@ -225,7 +225,7 @@ 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
@ -255,7 +255,7 @@ 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
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
@ -277,9 +277,9 @@ 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
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
@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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 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.
@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
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 Library General
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -1,3 +1,32 @@
2014-05-05 Dmitry Kasatkin <d.kasatkin@samsung.com>
version 0.8
* Symbilic names for keyrings
* Hash list signing
* License text fix for using OpenSSL
* Help output fix
2014-02-17 Dmitry Kasatkin <d.kasatkin@samsung.com>
version 0.7
* Fix symbolic links related bugs
* Provide recursive fixing
* Provide recursive signing
* Move IMA verification to the library (first for LTP use)
* Support for target architecture data size
* Remove obsolete module signing code
* Code cleanup
2013-08-28 Dmitry Kasatkin <d.kasatkin@samsung.com>
version 0.6
* support for asymmetric crypto keys and new signature format (v2)
* fixes to set correct hash algo for digital signature v1
* uuid support for EVM
* signature verification support
* test scripts removed
* README updates
2012-05-18 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
version 0.3

View File

@ -1,7 +1,7 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation,
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
@ -309,9 +309,10 @@ causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf bug. Until the bug is fixed you can use this workaround:
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
@ -367,4 +368,3 @@ operates.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@ -1,6 +1,6 @@
SUBDIRS = src tests
SUBDIRS = src
#EXTRA_DIST = LEGAL acinclude.m4 include
EXTRA_DIST = autogen.sh
ACLOCAL_AMFLAGS = -I m4
@ -11,7 +11,6 @@ pkgname = $(PACKAGE_NAME)-$(PACKAGE_VERSION)
tarname = $(pkgname).tar.gz
$(tarname):
git tag v$(PACKAGE_VERSION)
git archive --format=tar --prefix=$(pkgname)/ v$(PACKAGE_VERSION) $(FILES) | gzip >$@
tar: $(tarname)

163
README
View File

@ -1,52 +1,155 @@
ima-evm-utils - IMA/EVM signing utility
=========================================
1. Generate private key
Contents:
# plain key
openssl genrsa -out privkey_evm.pem 1024
1. Key and signature formats
2. Key generation
3. Initialization
4. Signing
# encrypted key
openssl genrsa -des3 -out privkey_evm.pem 1024
# set password for the key
openssl rsa -in /etc/keys/privkey_evm.pem -out privkey_evm_enc.pem -des3
Key and signature formats
-------------------------
EVM support (v2) in latest version of the kernel adds the file system UUID to
the HMAC calculation. It is controlled by the CONFIG_EVM_HMAC_VERSION and
version 2 is enabled by default. In this version default UUID is included by
default. Custom value can be supplied via '--uuid=UUID' or '-uUUID' parameter
to the 'sign' command. To use old format HMAC format use '-' as a parameter.
Latest kernel got IMA/EVM support for using X509 certificates and asymmetric key
support for verifying digital signatures. This version uses x509 format by default.
Use '--rsa' or '-1' parameter to use old signature format and API.
Key generation
--------------
Generate private key in plain text format
$ openssl genrsa -out privkey_evm.pem 1024
Generate encrypted private key
$ openssl genrsa -des3 -out privkey_evm.pem 1024
Make encrypted private key from unencrypted
$ openssl rsa -in /etc/keys/privkey_evm.pem -out privkey_evm_enc.pem -des3
Generate self-signed X509 certificate and private key for using kernel asymmetric
keys support
$ openssl req -new -nodes -utf8 -sha1 -days 36500 -batch \
-x509 -config x509_evm.genkey \
-outform DER -out x509_evm.der -keyout privkey_evm.pem
Configuration file x509_evm.genkey:
# Begining of the file
[ req ]
default_bits = 1024
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = myexts
[ req_distinguished_name ]
O = Magrathea
CN = Glacier signing key
emailAddress = slartibartfast@magrathea.h2g2
[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
# EOF
Get public key
$ openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem
Copy keys to /etc/keys
$ cp pubkey_evm.pem /etc/keys
$ scp pubkey_evm.pem target:/etc/keys
or
openssl pkcs8 -topk8 -in /etc/keys/privkey_evm.pem -out privkey_evm_enc.pem
$ cp x509_evm.pem /etc/keys
$ scp x509_evm.pem target:/etc/keys
2. Generate public key
openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem
Generation of EVM keys
3. Copy public (+private if to sign on device) key to the device/qemu /etc/keys
$ # create and save the kernel master key (user type)
$ keyctl add user kmk "`dd if=/dev/urandom bs=1 count=32 2>/dev/null`" @u
$ keyctl pipe `keyctl search @u user kmk` > /etc/keys/kmk
$ # create the EVM encrypted key
$ keyctl add encrypted evm-key "new user:kmk 32" @u
$ keyctl pipe `keyctl search @u encrypted evm-key` >/etc/keys/evm-key
scp pubkey_evm.pem mad:/etc/keys
4. Load keys and enable EVM
Initialization
--------------
evm_enable.sh
IMA/EVM initialization should be normally done from initial RAM file system
before mounting root filesystem.
This should be done at early phase, before mounting root filesystem.
Here is an example script /etc/initramfs-tools/scripts/local-top/ima.sh
5. Sign EVM and use hash value for IMA - common case
# import EVM HMAC key
keyctl clear @u
cat /etc/keys/kmk | keyctl padd user kmk @u
keyctl add encrypted evm-key "load `cat /etc/keys/evm-key`" @u
evmctl sign --imahash test.txt
# import IMA public key
ima_id=`keyctl newring _ima @u`
evmctl --rsa import /etc/keys/pubkey_evm.pem $ima_id
6. Sign IMA and EVM - for immutable files and modules
# import EVM public key
evm_id=`keyctl newring _evm @u`
evmctl --rsa import /etc/keys/pubkey_evm.pem $evm_id
evmctl sign --imasig test.txt
# enable EVM
echo "1" > /sys/kernel/security/evm
7. Sign whole filesystem
evm_sign_all.sh
or
find / \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) ! -path "/lib/modules/*" -type f -uid 0 -exec evmctl sign --imahash '{}' \;
find /lib/modules ! -name "*.ko" -type f -uid 0 -exec evmctl sign --imahash '{}' \;
# security.ima needs to have signature for modules
find /lib/modules -name "*.ko" -type f -uid 0 -exec evmctl sign --imasig '{}' \;
Import X509 certificate into the kernel keyring (since kernel 3.9?)
# generate signatures in .sig files
find /lib/modules -name "*.ko" -type f -uid 0 -exec evmctl -n --sigfile ima_sign '{}' \;
$ evmctl import /etc/keys/x509_evm.der `keyctl search @u keyring _ima`
$ evmctl import /etc/keys/x509_evm.der `keyctl search @u keyring _evm`
8. Label filesystem in fix mode...
ima_fix_dir.sh <dir>
Signing
-------
Default public key: /etc/keys/pubkey_evm.pem
Default private key: /etc/keys/privkey_evm.pem
Default X509 certificate: /etc/keys/x509_evm.der
Signing for using old RSA format is done using '-1' or '--rsa' parameter.
Signing for using old EVM HMAC format is done using '-u-' or '--uuid=-' parameter.
Sign file with EVM signature and use hash value for IMA - common case
$ evmctl sign [-u] [-1] --imahash test.txt
Sign file with both IMA and EVM signatures - for immutable files
$ evmctl sign [-u] [-1] --imasig test.txt
Sign file with IMA signature - for immutable files
$ evmctl ima_sign [-1] test.txt
Label whole filesystem with EVM signatures
$ find / \( -fstype rootfs -o -fstype ext4 \) -exec evmctl sign [-u] [-1] --imahash '{}' \;
Label filesystem in fix mode - kernel sets correct values to IMA and EVM xattrs
$ find / \( -fstype rootfs -o -fstype ext4 \) -exec sh -c "< '{}'" \;

View File

@ -1,8 +1,8 @@
# autoconf script
AC_PREREQ([2.65])
AC_INIT(ima-evm-utils, 0.3, dmitry.kasatkin@intel.com)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
AC_INIT(ima-evm-utils, 0.8, d.kasatkin@samsung.com)
AM_INIT_AUTOMAKE
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
@ -30,6 +30,9 @@ AC_SUBST(OPENSSL_LIBS)
AC_CHECK_HEADER(unistd.h)
AC_CHECK_HEADERS(openssl/conf.h)
AC_CHECK_HEADERS(attr/xattr.h, , [AC_MSG_ERROR([attr/xattr.h header not found. You need the libattr development package.])])
AC_CHECK_HEADERS(keyutils.h, , [AC_MSG_ERROR([keyutils.h header not found. You need the libkeyutils development package.])])
#debug support - yes for a while
PKG_ARG_ENABLE(debug, "yes", DEBUG, [Enable Debug support])
if test $pkg_cv_enable_debug = yes; then
@ -46,8 +49,7 @@ fi
AC_CONFIG_FILES([Makefile
src/Makefile
tests/Makefile
ima-evm-utils.spec
packaging/ima-evm-utils.spec
])
AC_OUTPUT

29
examples/ima-gen-local-ca.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
GENKEY=ima-local-ca.genkey
cat << __EOF__ >$GENKEY
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = v3_ca
[ req_distinguished_name ]
O = IMA-CA
CN = IMA/EVM certificate signing key
emailAddress = ca@ima-ca
[ v3_ca ]
basicConstraints=CA:TRUE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
# keyUsage = cRLSign, keyCertSign
__EOF__
openssl req -new -x509 -utf8 -sha1 -days 3650 -batch -config $GENKEY \
-outform DER -out ima-local-ca.x509 -keyout ima-local-ca.priv
openssl x509 -inform DER -in ima-local-ca.x509 -out ima-local-ca.pem

29
examples/ima-genkey-self.sh Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
GENKEY=x509_evm.genkey
cat << __EOF__ >$GENKEY
[ req ]
default_bits = 1024
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = myexts
[ req_distinguished_name ]
O = `hostname`
CN = `whoami` signing key
emailAddress = `whoami`@`hostname`
[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
__EOF__
openssl req -x509 -new -nodes -utf8 -sha1 -days 3650 -batch -config $GENKEY \
-outform DER -out x509_evm.der -keyout privkey_evm.pem
openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem

33
examples/ima-genkey.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/sh
GENKEY=ima.genkey
cat << __EOF__ >$GENKEY
[ req ]
default_bits = 1024
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = v3_usr
[ req_distinguished_name ]
O = `hostname`
CN = `whoami` signing key
emailAddress = `whoami`@`hostname`
[ v3_usr ]
basicConstraints=critical,CA:FALSE
#basicConstraints=CA:FALSE
keyUsage=digitalSignature
#keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
#authorityKeyIdentifier=keyid,issuer
__EOF__
openssl req -new -nodes -utf8 -sha1 -days 365 -batch -config $GENKEY \
-out csr_ima.pem -keyout privkey_ima.pem
openssl x509 -req -in csr_ima.pem -days 365 -extfile $GENKEY -extensions v3_usr \
-CA ima-local-ca.pem -CAkey ima-local-ca.priv -CAcreateserial \
-outform DER -out x509_ima.der

View File

@ -0,0 +1,53 @@
Name: ima-evm-utils
Version: 0.8
Release: 1%{?dist}
Summary: ima-evm-utils - IMA/EVM control utility
Group: System/Libraries
License: GPLv2
#URL:
Source0: %{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: openssl-devel
BuildRequires: libattr-devel
BuildRequires: keyutils-libs-devel
%description
This package provide IMA/EVM control utility
%prep
%setup -q
%build
./autogen.sh
%configure --prefix=/usr
make
%install
rm -rf %{buildroot}
make DESTDIR=%{buildroot} install
%clean
rm -rf %{buildroot}
%post
/sbin/ldconfig
exit 0
%preun -p /sbin/ldconfig
%postun
/sbin/ldconfig
%files
%defattr(-,root,root,-)
%{_bindir}/*
%{_libdir}/libimaevm.*
%{_includedir}/*
%changelog
* Thu Apr 05 2012 Dmitry Kasatkin <dmitry.kasatkin@intel.com>
- Initial RPM spec file

View File

@ -3,7 +3,7 @@ Version: @PACKAGE_VERSION@
Release: 1%{?dist}
Summary: @PACKAGE_NAME@ - IMA/EVM control utility
Group: System/Libraries
License: LGPLv2
License: GPLv2
#URL:
Source0: %{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
@ -44,7 +44,8 @@ exit 0
%files
%defattr(-,root,root,-)
%{_bindir}/*
%{_libdir}/*
%{_libdir}/libimaevm.*
%{_includedir}/*
%changelog
* Thu Apr 05 2012 Dmitry Kasatkin <dmitry.kasatkin@intel.com>

View File

@ -1,10 +1,20 @@
lib_LTLIBRARIES = libimaevm.la
libimaevm_la_SOURCES = libimaevm.c
libimaevm_la_CPPFLAGS = $(OPENSSL_CFLAGS)
# current[:revision[:age]]
# result: [current-age].age.revision
libimaevm_la_LDFLAGS = -version-info 0:0:0
libimaevm_la_LIBADD = $(OPENSSL_LIBS)
include_HEADERS = imaevm.h
bin_PROGRAMS = evmctl
evmctl_SOURCES = evmctl.c
evmctl_CPPFLAGS = $(OPENSSL_CFLAGS)
evmctl_LDFLAGS = $(LDFLAGS_READLINE)
evmctl_LDADD = $(OPENSSL_LIBS) -lkeyutils
evmctl_LDADD = $(OPENSSL_LIBS) -lkeyutils libimaevm.la
INCLUDES = -I$(top_srcdir) -include config.h

File diff suppressed because it is too large Load Diff

195
src/imaevm.h Normal file
View File

@ -0,0 +1,195 @@
/*
* ima-evm-utils - IMA/EVM support utilities
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011,2012,2013 Intel Corporation
* Copyright (C) 2013,2014 Samsung Electronics
*
* Authors:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* <dmitry.kasatkin@intel.com>
* <d.kasatkin@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*
* File: imaevm.h
* IMA/EVM header file
*/
#ifndef _LIBIMAEVM_H
#define _LIBIMAEVM_H
#include <stdint.h>
#include <syslog.h>
#include <stdbool.h>
#include <errno.h>
#include <openssl/rsa.h>
#ifdef USE_FPRINTF
#define do_log(level, fmt, args...) ({ if (level <= params.verbose) fprintf(stderr, fmt, ##args); })
#define do_log_dump(level, p, len, cr) ({ if (level <= params.verbose) do_dump(stderr, p, len, cr); })
#else
#define do_log(level, fmt, args...) syslog(level, fmt, ##args)
#define do_log_dump(level, p, len, cr)
#endif
#ifdef DEBUG
#define log_debug(fmt, args...) do_log(LOG_DEBUG, "%s:%d " fmt, __func__ , __LINE__ , ##args)
#define log_debug_dump(p, len) do_log_dump(LOG_DEBUG, p, len, true)
#define log_debug_dump_n(p, len) do_log_dump(LOG_DEBUG, p, len, false)
#else
#define log_debug(fmt, args...)
#define log_debug_dump(p, len)
#endif
#define log_dump(p, len) do_log_dump(LOG_INFO, p, len, true)
#define log_dump_n(p, len) do_log_dump(LOG_INFO, p, len, false)
#define log_info(fmt, args...) do_log(LOG_INFO, fmt, ##args)
#define log_err(fmt, args...) do_log(LOG_ERR, fmt, ##args)
#define log_errno(fmt, args...) do_log(LOG_ERR, fmt ": errno: %s (%d)\n", ##args, strerror(errno), errno)
#define DATA_SIZE 4096
#define SHA1_HASH_LEN 20
#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
#define EXT34_IOC_GETVERSION _IOR('f', 3, long)
#define FS_IOC_GETFLAGS _IOR('f', 1, long)
#define FS_IOC_SETFLAGS _IOW('f', 2, long)
#define FS_IOC32_GETFLAGS _IOR('f', 1, int)
#define FS_IOC32_SETFLAGS _IOW('f', 2, int)
#define __packed __attribute__((packed))
struct h_misc {
unsigned long ino;
uint32_t generation;
uid_t uid;
gid_t gid;
unsigned short mode;
};
struct h_misc_32 {
uint32_t ino;
uint32_t generation;
uid_t uid;
gid_t gid;
unsigned short mode;
};
struct h_misc_64 {
uint64_t ino;
uint32_t generation;
uid_t uid;
gid_t gid;
unsigned short mode;
};
enum pubkey_algo {
PUBKEY_ALGO_RSA,
PUBKEY_ALGO_MAX,
};
enum digest_algo {
DIGEST_ALGO_SHA1,
DIGEST_ALGO_SHA256,
DIGEST_ALGO_MAX
};
enum digsig_version {
DIGSIG_VERSION_1 = 1,
DIGSIG_VERSION_2
};
struct pubkey_hdr {
uint8_t version; /* key format version */
uint32_t timestamp; /* key made, always 0 for now */
uint8_t algo;
uint8_t nmpi;
char mpi[0];
} __packed;
struct signature_hdr {
uint8_t version; /* signature format version */
uint32_t timestamp; /* signature made */
uint8_t algo;
uint8_t hash;
uint8_t keyid[8];
uint8_t nmpi;
char mpi[0];
} __packed;
enum pkey_hash_algo {
PKEY_HASH_MD4,
PKEY_HASH_MD5,
PKEY_HASH_SHA1,
PKEY_HASH_RIPE_MD_160,
PKEY_HASH_SHA256,
PKEY_HASH_SHA384,
PKEY_HASH_SHA512,
PKEY_HASH_SHA224,
PKEY_HASH__LAST
};
/*
* signature format v2 - for using with asymmetric keys
*/
struct signature_v2_hdr {
uint8_t version; /* signature format version */
uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */
uint32_t keyid; /* IMA key identifier - not X509/PGP specific*/
uint16_t sig_size; /* signature size */
uint8_t sig[0]; /* signature payload */
} __packed;
typedef int (*verify_hash_fn_t)(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile);
struct libevm_params {
int verbose;
const char *hash_algo;
char *keyfile;
};
struct RSA_ASN1_template {
const uint8_t *data;
size_t size;
};
extern const struct RSA_ASN1_template RSA_ASN1_templates[PKEY_HASH__LAST];
extern struct libevm_params params;
void do_dump(FILE *fp, const void *ptr, int len, bool cr);
void dump(const void *ptr, int len);
int get_filesize(const char *filename);
int ima_calc_hash(const char *file, uint8_t *hash);
int get_hash_algo(const char *algo);
RSA *read_pub_key(const char *keyfile, int x509);
int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen);
int ima_verify_signature(const char *file, unsigned char *sig, int siglen);
#endif

535
src/libimaevm.c Normal file
View File

@ -0,0 +1,535 @@
/*
* ima-evm-utils - IMA/EVM support utilities
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011,2012,2013 Intel Corporation
* Copyright (C) 2013,2014 Samsung Electronics
*
* Authors:
* Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
* <dmitry.kasatkin@intel.com>
* <d.kasatkin@samsung.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*
* File: libimaevm.c
* IMA/EVM library
*/
/* should we use logger instead for library? */
#define USE_FPRINTF
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include "imaevm.h"
const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
[PKEY_HASH_MD4] = "md4",
[PKEY_HASH_MD5] = "md5",
[PKEY_HASH_SHA1] = "sha1",
[PKEY_HASH_RIPE_MD_160] = "rmd160",
[PKEY_HASH_SHA256] = "sha256",
[PKEY_HASH_SHA384] = "sha384",
[PKEY_HASH_SHA512] = "sha512",
[PKEY_HASH_SHA224] = "sha224",
};
/*
* Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
*/
static const uint8_t RSA_digest_info_MD5[] = {
0x30, 0x20, 0x30, 0x0C, 0x06, 0x08,
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */
0x05, 0x00, 0x04, 0x10
};
static const uint8_t RSA_digest_info_SHA1[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
0x2B, 0x0E, 0x03, 0x02, 0x1A,
0x05, 0x00, 0x04, 0x14
};
static const uint8_t RSA_digest_info_RIPE_MD_160[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
0x2B, 0x24, 0x03, 0x02, 0x01,
0x05, 0x00, 0x04, 0x14
};
static const uint8_t RSA_digest_info_SHA224[] = {
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
0x05, 0x00, 0x04, 0x1C
};
static const uint8_t RSA_digest_info_SHA256[] = {
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
0x05, 0x00, 0x04, 0x20
};
static const uint8_t RSA_digest_info_SHA384[] = {
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
0x05, 0x00, 0x04, 0x30
};
static const uint8_t RSA_digest_info_SHA512[] = {
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
0x05, 0x00, 0x04, 0x40
};
const struct RSA_ASN1_template RSA_ASN1_templates[PKEY_HASH__LAST] = {
#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
[PKEY_HASH_MD5] = _(MD5),
[PKEY_HASH_SHA1] = _(SHA1),
[PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160),
[PKEY_HASH_SHA256] = _(SHA256),
[PKEY_HASH_SHA384] = _(SHA384),
[PKEY_HASH_SHA512] = _(SHA512),
[PKEY_HASH_SHA224] = _(SHA224),
#undef _
};
struct libevm_params params = {
.verbose = LOG_INFO - 1,
.hash_algo = "sha1",
};
void do_dump(FILE *fp, const void *ptr, int len, bool cr)
{
int i;
uint8_t *data = (uint8_t *) ptr;
for (i = 0; i < len; i++)
fprintf(fp, "%02x", data[i]);
if (cr)
fprintf(fp, "\n");
}
void dump(const void *ptr, int len)
{
do_dump(stdout, ptr, len, true);
}
int get_filesize(const char *filename)
{
struct stat stats;
/* Need to know the file length */
stat(filename, &stats);
return (int)stats.st_size;
}
static inline int get_fdsize(int fd)
{
struct stat stats;
/* Need to know the file length */
fstat(fd, &stats);
return (int)stats.st_size;
}
static int add_file_hash(const char *file, EVP_MD_CTX *ctx)
{
uint8_t *data;
int err, size, bs = DATA_SIZE;
size_t len;
FILE *fp;
data = malloc(bs);
if (!data) {
log_err("malloc failed\n");
return -1;
}
fp = fopen(file, "r");
if (!fp) {
log_err("Unable to open %s\n", file);
return -1;
}
for (size = get_fdsize(fileno(fp)); size; size -= len) {
len = MIN(size, bs);
err = fread(data, len, 1, fp);
if (!err) {
if (ferror(fp)) {
log_err("fread() error\n\n");
return -1;
}
break;
}
err = EVP_DigestUpdate(ctx, data, len);
if (!err) {
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
}
fclose(fp);
free(data);
return 0;
}
static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
{
int err;
struct dirent *de;
DIR *dir;
unsigned long long ino, off;
unsigned int type;
dir = opendir(file);
if (!dir) {
log_err("Unable to open %s\n", file);
return -1;
}
while ((de = readdir(dir))) {
ino = de->d_ino;
off = de->d_off;
type = de->d_type;
log_debug("entry: %s, ino: %llu, type: %u, off: %llu, reclen: %hu\n",
de->d_name, ino, type, off, de->d_reclen);
err = EVP_DigestUpdate(ctx, de->d_name, strlen(de->d_name));
/*err |= EVP_DigestUpdate(ctx, &off, sizeof(off));*/
err |= EVP_DigestUpdate(ctx, &ino, sizeof(ino));
err |= EVP_DigestUpdate(ctx, &type, sizeof(type));
if (!err) {
log_err("EVP_DigestUpdate() failed\n");
return 1;
}
}
closedir(dir);
return 0;
}
static int add_link_hash(const char *path, EVP_MD_CTX *ctx)
{
int err;
char buf[1024];
err = readlink(path, buf, sizeof(buf));
if (err <= 0)
return -1;
log_info("link: %s -> %.*s\n", path, err, buf);
return !EVP_DigestUpdate(ctx, buf, err);
}
static int add_dev_hash(struct stat *st, EVP_MD_CTX *ctx)
{
uint32_t dev = st->st_rdev;
unsigned major = (dev & 0xfff00) >> 8;
unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
log_info("device: %u:%u\n", major, minor);
return !EVP_DigestUpdate(ctx, &dev, sizeof(dev));
}
int ima_calc_hash(const char *file, uint8_t *hash)
{
struct stat st;
EVP_MD_CTX ctx;
const EVP_MD *md;
unsigned int mdlen;
int err;
/* Need to know the file length */
err = lstat(file, &st);
if (err < 0) {
log_err("stat() failed\n");
return err;
}
md = EVP_get_digestbyname(params.hash_algo);
if (!md) {
log_err("EVP_get_digestbyname() failed\n");
return 1;
}
err = EVP_DigestInit(&ctx, md);
if (!err) {
log_err("EVP_DigestInit() failed\n");
return 1;
}
switch (st.st_mode & S_IFMT) {
case S_IFREG:
err = add_file_hash(file, &ctx);
break;
case S_IFDIR:
err = add_dir_hash(file, &ctx);
break;
case S_IFLNK:
err = add_link_hash(file, &ctx);
break;
case S_IFIFO: case S_IFSOCK:
case S_IFCHR: case S_IFBLK:
err = add_dev_hash(&st, &ctx);
break;
default:
log_errno("Unsupported file type");
return -1;
}
if (err)
return err;
err = EVP_DigestFinal(&ctx, hash, &mdlen);
if (!err) {
log_err("EVP_DigestFinal() failed\n");
return 1;
}
return mdlen;
}
RSA *read_pub_key(const char *keyfile, int x509)
{
FILE *fp;
RSA *key = NULL;
X509 *crt = NULL;
EVP_PKEY *pkey = NULL;
fp = fopen(keyfile, "r");
if (!fp) {
log_err("Unable to open keyfile %s\n", keyfile);
return NULL;
}
if (x509) {
crt = d2i_X509_fp(fp, NULL);
if (!crt) {
log_err("d2i_X509_fp() failed\n");
goto out;
}
pkey = X509_extract_key(crt);
if (!pkey) {
log_err("X509_extract_key() failed\n");
goto out;
}
key = EVP_PKEY_get1_RSA(pkey);
} else {
key = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
}
if (!key)
log_err("PEM_read_RSA_PUBKEY() failed\n");
out:
if (pkey)
EVP_PKEY_free(pkey);
if (crt)
X509_free(crt);
fclose(fp);
return key;
}
int verify_hash_v1(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile)
{
int err, len;
SHA_CTX ctx;
unsigned char out[1024];
RSA *key;
unsigned char sighash[20];
struct signature_hdr *hdr = (struct signature_hdr *)sig;
log_info("hash: ");
log_dump(hash, size);
key = read_pub_key(keyfile, 0);
if (!key)
return 1;
SHA1_Init(&ctx);
SHA1_Update(&ctx, hash, size);
SHA1_Update(&ctx, hdr, sizeof(*hdr));
SHA1_Final(sighash, &ctx);
log_info("sighash: ");
log_dump(sighash, sizeof(sighash));
err = RSA_public_decrypt(siglen - sizeof(*hdr) - 2, sig + sizeof(*hdr) + 2, out, key, RSA_PKCS1_PADDING);
RSA_free(key);
if (err < 0) {
log_err("RSA_public_decrypt() failed: %d\n", err);
return 1;
}
len = err;
if (len != sizeof(sighash) || memcmp(out, sighash, len) != 0) {
log_err("Verification failed: %d\n", err);
return -1;
} else {
/*log_info("Verification is OK\n");*/
printf("Verification is OK\n");
}
return 0;
}
int verify_hash_v2(const unsigned char *hash, int size, unsigned char *sig, int siglen, const char *keyfile)
{
int err, len;
unsigned char out[1024];
RSA *key;
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
const struct RSA_ASN1_template *asn1;
log_info("hash: ");
log_dump(hash, size);
key = read_pub_key(keyfile, 1);
if (!key)
return 1;
err = RSA_public_decrypt(siglen - sizeof(*hdr), sig + sizeof(*hdr), out, key, RSA_PKCS1_PADDING);
RSA_free(key);
if (err < 0) {
log_err("RSA_public_decrypt() failed: %d\n", err);
return 1;
}
len = err;
asn1 = &RSA_ASN1_templates[hdr->hash_algo];
if (len < asn1->size || memcmp(out, asn1->data, asn1->size)) {
log_err("Verification failed: %d\n", err);
return -1;
}
len -= asn1->size;
if (len != size || memcmp(out + asn1->size, hash, len)) {
log_err("Verification failed: %d\n", err);
return -1;
}
/*log_info("Verification is OK\n");*/
printf("Verification is OK\n");
return 0;
}
int get_hash_algo(const char *algo)
{
int i;
for (i = 0; i < PKEY_HASH__LAST; i++)
if (!strcmp(algo, pkey_hash_algo[i]))
return i;
return PKEY_HASH_SHA1;
}
static int get_hash_algo_from_sig(unsigned char *sig)
{
uint8_t hashalgo;
if (sig[0] == 1) {
hashalgo = ((struct signature_hdr *)sig)->hash;
if (hashalgo >= DIGEST_ALGO_MAX)
return -1;
switch (hashalgo) {
case DIGEST_ALGO_SHA1:
return PKEY_HASH_SHA1;
case DIGEST_ALGO_SHA256:
return PKEY_HASH_SHA256;
default:
return -1;
}
} else if (sig[0] == 2) {
hashalgo = ((struct signature_v2_hdr *)sig)->hash_algo;
if (hashalgo >= PKEY_HASH__LAST)
return -1;
return hashalgo;
} else
return -1;
}
int verify_hash(const unsigned char *hash, int size, unsigned char *sig, int siglen)
{
char *key;
int x509;
verify_hash_fn_t verify_hash;
/* Get signature type from sig header */
if (sig[0] == DIGSIG_VERSION_1) {
verify_hash = verify_hash_v1;
/* Read pubkey from RSA key */
x509 = 0;
} else if (sig[0] == DIGSIG_VERSION_2) {
verify_hash = verify_hash_v2;
/* Read pubkey from x509 cert */
x509 = 1;
} else
return -1;
/* Determine what key to use for verification*/
key = params.keyfile ? : x509 ?
"/etc/keys/x509_evm.der" :
"/etc/keys/pubkey_evm.pem";
return verify_hash(hash, size, sig, siglen, key);
}
int ima_verify_signature(const char *file, unsigned char *sig, int siglen)
{
unsigned char hash[64];
int hashlen, sig_hash_algo;
if (sig[0] != 0x03) {
log_err("security.ima has no signature\n");
return -1;
}
sig_hash_algo = get_hash_algo_from_sig(sig + 1);
if (sig_hash_algo < 0) {
log_err("Invalid signature\n");
return -1;
}
/* Use hash algorithm as retrieved from signature */
params.hash_algo = pkey_hash_algo[sig_hash_algo];
hashlen = ima_calc_hash(file, hash);
if (hashlen <= 1)
return hashlen;
return verify_hash(hash, hashlen, sig + 1, siglen - 1);
}

View File

@ -1,7 +0,0 @@
pkglibexec_PROGRAMS = openclose
openclose_SOURCES = openclose.c
dist_pkglibexec_SCRIPTS = evm_enable.sh evm_genkey.sh evm_sign_all.sh evm_sign_modules.sh \
ima_fix_dir.sh evm_hmac_all.sh evm_hmac_modules.sh

View File

@ -1,25 +0,0 @@
#!/bin/sh
# import EVM HMAC key
keyctl clear @u
keyctl add user kmk "testing123" @u
keyctl add encrypted evm-key "load `cat /etc/keys/evm-key`" @u
# import Moule public key
mod_id=`keyctl newring _module @u`
evmctl import /etc/keys/pubkey_evm.pem $mod_id
# import IMA public key
ima_id=`keyctl newring _ima @u`
evmctl import /etc/keys/pubkey_evm.pem $ima_id
# import EVM public key
evm_id=`keyctl newring _evm @u`
evmctl import /etc/keys/pubkey_evm.pem $evm_id
# enable EVM
echo "1" > /sys/kernel/security/evm
# enable module checking
echo "1" > /sys/kernel/security/ima/module_check

View File

@ -1,8 +0,0 @@
#!/bin/sh
keyctl add user kmk "testing123" @u
key=`keyctl add encrypted evm-key "new user:kmk 32" @u`
keyctl print $key >/etc/keys/evm-key
keyctl list @u

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/}
echo "Label: $dir"
find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) \( -type f -o -type d \) -exec evmctl hmac --imahash $verbose '{}' \;

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/lib/modules}
echo "HMAC modules: $dir"
find $dir -name "*.ko" -type f -exec evmctl hmac --imasig $verbose '{}' \;

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/}
echo "Label: $dir"
find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) -type f -exec evmctl sign --imahash $verbose '{}' \;

View File

@ -1,14 +0,0 @@
#!/bin/sh
verbose=""
if [ "$1" = "-v" ] ; then
verbose="-v"
shift 1
fi
dir=${1:-/lib/modules}
echo "Signing modules: $dir"
find $dir -name "*.ko" -type f -exec evmctl sign --imasig $verbose '{}' \;

View File

@ -1,8 +0,0 @@
#!/bin/sh
dir=${1:-/}
echo "Fixing dir: $dir"
find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) -type f -exec openclose '{}' \;

View File

@ -1,20 +0,0 @@
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int fd;
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open()");
exit(1);
}
close(fd);
return 0;
}