evmctl - IMA/EVM control tool
evmctl provides signing support for IMA/EVM. Functionality includes signing of file content (IMA), file metadata (EVM), importing public keys into kernel keyring. Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
This commit is contained in:
		
							
								
								
									
										53
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| *.swp | ||||
| *~ | ||||
|  | ||||
| # Generated by autotools | ||||
| .deps | ||||
| aclocal.m4 | ||||
| autom4te.cache | ||||
| config.guess | ||||
| config.log | ||||
| config.status | ||||
| config.sub | ||||
| configure | ||||
| depcomp | ||||
| install-sh | ||||
| Makefile.in | ||||
| Makefile | ||||
| !tests/data/Makefile | ||||
| missing | ||||
| compile | ||||
| libtool | ||||
| ltmain.sh | ||||
|  | ||||
| # Compiled executables | ||||
| *.o | ||||
| *.a | ||||
| src/evmctl | ||||
| tests/openclose | ||||
| config.h | ||||
| config.h.in | ||||
| stamp-h1 | ||||
| *.spec | ||||
|  | ||||
| # But don't ignore the symlinks with the same names in this directory | ||||
| !tests/valgrind/* | ||||
|  | ||||
| # cscope/tags | ||||
| tags | ||||
| TAGS | ||||
| cscope.* | ||||
| ncscope.* | ||||
|  | ||||
| # Generated documentation | ||||
| *.8 | ||||
| *.5 | ||||
| manpage.links | ||||
| manpage.refs | ||||
|  | ||||
| # quilt's files | ||||
| patches | ||||
| series | ||||
|  | ||||
| # test output | ||||
|  | ||||
							
								
								
									
										5
									
								
								ChangeLog
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								ChangeLog
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| 2011-08-24  Dmitry Kasatkin  <dmitry.kasatkin@intel.com> | ||||
|  | ||||
| 	version 0.1 | ||||
| 	* Initial public version. | ||||
|  | ||||
							
								
								
									
										365
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								INSTALL
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,365 @@ | ||||
| Installation Instructions | ||||
| ************************* | ||||
|  | ||||
| Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, | ||||
| 2006, 2007, 2008, 2009 Free Software Foundation, Inc. | ||||
|  | ||||
|    Copying and distribution of this file, with or without modification, | ||||
| are permitted in any medium without royalty provided the copyright | ||||
| notice and this notice are preserved.  This file is offered as-is, | ||||
| without warranty of any kind. | ||||
|  | ||||
| Basic Installation | ||||
| ================== | ||||
|  | ||||
|    Briefly, the shell commands `./configure; make; make install' should | ||||
| configure, build, and install this package.  The following | ||||
| more-detailed instructions are generic; see the `README' file for | ||||
| instructions specific to this package.  Some packages provide this | ||||
| `INSTALL' file but do not implement all of the features documented | ||||
| below.  The lack of an optional feature in a given package is not | ||||
| necessarily a bug.  More recommendations for GNU packages can be found | ||||
| in *note Makefile Conventions: (standards)Makefile Conventions. | ||||
|  | ||||
|    The `configure' shell script attempts to guess correct values for | ||||
| various system-dependent variables used during compilation.  It uses | ||||
| those values to create a `Makefile' in each directory of the package. | ||||
| It may also create one or more `.h' files containing system-dependent | ||||
| definitions.  Finally, it creates a shell script `config.status' that | ||||
| you can run in the future to recreate the current configuration, and a | ||||
| file `config.log' containing compiler output (useful mainly for | ||||
| debugging `configure'). | ||||
|  | ||||
|    It can also use an optional file (typically called `config.cache' | ||||
| and enabled with `--cache-file=config.cache' or simply `-C') that saves | ||||
| the results of its tests to speed up reconfiguring.  Caching is | ||||
| disabled by default to prevent problems with accidental use of stale | ||||
| cache files. | ||||
|  | ||||
|    If you need to do unusual things to compile the package, please try | ||||
| to figure out how `configure' could check whether to do them, and mail | ||||
| diffs or instructions to the address given in the `README' so they can | ||||
| be considered for the next release.  If you are using the cache, and at | ||||
| some point `config.cache' contains results you don't want to keep, you | ||||
| may remove or edit it. | ||||
|  | ||||
|    The file `configure.ac' (or `configure.in') is used to create | ||||
| `configure' by a program called `autoconf'.  You need `configure.ac' if | ||||
| you want to change it or regenerate `configure' using a newer version | ||||
| of `autoconf'. | ||||
|  | ||||
|    The simplest way to compile this package is: | ||||
|  | ||||
|   1. `cd' to the directory containing the package's source code and type | ||||
|      `./configure' to configure the package for your system. | ||||
|  | ||||
|      Running `configure' might take a while.  While running, it prints | ||||
|      some messages telling which features it is checking for. | ||||
|  | ||||
|   2. Type `make' to compile the package. | ||||
|  | ||||
|   3. Optionally, type `make check' to run any self-tests that come with | ||||
|      the package, generally using the just-built uninstalled binaries. | ||||
|  | ||||
|   4. Type `make install' to install the programs and any data files and | ||||
|      documentation.  When installing into a prefix owned by root, it is | ||||
|      recommended that the package be configured and built as a regular | ||||
|      user, and only the `make install' phase executed with root | ||||
|      privileges. | ||||
|  | ||||
|   5. Optionally, type `make installcheck' to repeat any self-tests, but | ||||
|      this time using the binaries in their final installed location. | ||||
|      This target does not install anything.  Running this target as a | ||||
|      regular user, particularly if the prior `make install' required | ||||
|      root privileges, verifies that the installation completed | ||||
|      correctly. | ||||
|  | ||||
|   6. You can remove the program binaries and object files from the | ||||
|      source code directory by typing `make clean'.  To also remove the | ||||
|      files that `configure' created (so you can compile the package for | ||||
|      a different kind of computer), type `make distclean'.  There is | ||||
|      also a `make maintainer-clean' target, but that is intended mainly | ||||
|      for the package's developers.  If you use it, you may have to get | ||||
|      all sorts of other programs in order to regenerate files that came | ||||
|      with the distribution. | ||||
|  | ||||
|   7. Often, you can also type `make uninstall' to remove the installed | ||||
|      files again.  In practice, not all packages have tested that | ||||
|      uninstallation works correctly, even though it is required by the | ||||
|      GNU Coding Standards. | ||||
|  | ||||
|   8. Some packages, particularly those that use Automake, provide `make | ||||
|      distcheck', which can by used by developers to test that all other | ||||
|      targets like `make install' and `make uninstall' work correctly. | ||||
|      This target is generally not run by end users. | ||||
|  | ||||
| Compilers and Options | ||||
| ===================== | ||||
|  | ||||
|    Some systems require unusual options for compilation or linking that | ||||
| the `configure' script does not know about.  Run `./configure --help' | ||||
| for details on some of the pertinent environment variables. | ||||
|  | ||||
|    You can give `configure' initial values for configuration parameters | ||||
| by setting variables in the command line or in the environment.  Here | ||||
| is an example: | ||||
|  | ||||
|      ./configure CC=c99 CFLAGS=-g LIBS=-lposix | ||||
|  | ||||
|    *Note Defining Variables::, for more details. | ||||
|  | ||||
| Compiling For Multiple Architectures | ||||
| ==================================== | ||||
|  | ||||
|    You can compile the package for more than one kind of computer at the | ||||
| same time, by placing the object files for each architecture in their | ||||
| own directory.  To do this, you can use GNU `make'.  `cd' to the | ||||
| directory where you want the object files and executables to go and run | ||||
| the `configure' script.  `configure' automatically checks for the | ||||
| source code in the directory that `configure' is in and in `..'.  This | ||||
| is known as a "VPATH" build. | ||||
|  | ||||
|    With a non-GNU `make', it is safer to compile the package for one | ||||
| architecture at a time in the source code directory.  After you have | ||||
| installed the package for one architecture, use `make distclean' before | ||||
| reconfiguring for another architecture. | ||||
|  | ||||
|    On MacOS X 10.5 and later systems, you can create libraries and | ||||
| executables that work on multiple system types--known as "fat" or | ||||
| "universal" binaries--by specifying multiple `-arch' options to the | ||||
| compiler but only a single `-arch' option to the preprocessor.  Like | ||||
| this: | ||||
|  | ||||
|      ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ | ||||
|                  CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ | ||||
|                  CPP="gcc -E" CXXCPP="g++ -E" | ||||
|  | ||||
|    This is not guaranteed to produce working output in all cases, you | ||||
| may have to build one architecture at a time and combine the results | ||||
| using the `lipo' tool if you have problems. | ||||
|  | ||||
| Installation Names | ||||
| ================== | ||||
|  | ||||
|    By default, `make install' installs the package's commands under | ||||
| `/usr/local/bin', include files under `/usr/local/include', etc.  You | ||||
| can specify an installation prefix other than `/usr/local' by giving | ||||
| `configure' the option `--prefix=PREFIX', where PREFIX must be an | ||||
| absolute file name. | ||||
|  | ||||
|    You can specify separate installation prefixes for | ||||
| architecture-specific files and architecture-independent files.  If you | ||||
| pass the option `--exec-prefix=PREFIX' to `configure', the package uses | ||||
| PREFIX as the prefix for installing programs and libraries. | ||||
| Documentation and other data files still use the regular prefix. | ||||
|  | ||||
|    In addition, if you use an unusual directory layout you can give | ||||
| options like `--bindir=DIR' to specify different values for particular | ||||
| kinds of files.  Run `configure --help' for a list of the directories | ||||
| you can set and what kinds of files go in them.  In general, the | ||||
| default for these options is expressed in terms of `${prefix}', so that | ||||
| specifying just `--prefix' will affect all of the other directory | ||||
| specifications that were not explicitly provided. | ||||
|  | ||||
|    The most portable way to affect installation locations is to pass the | ||||
| correct locations to `configure'; however, many packages provide one or | ||||
| both of the following shortcuts of passing variable assignments to the | ||||
| `make install' command line to change installation locations without | ||||
| having to reconfigure or recompile. | ||||
|  | ||||
|    The first method involves providing an override variable for each | ||||
| affected directory.  For example, `make install | ||||
| prefix=/alternate/directory' will choose an alternate location for all | ||||
| directory configuration variables that were expressed in terms of | ||||
| `${prefix}'.  Any directories that were specified during `configure', | ||||
| but not in terms of `${prefix}', must each be overridden at install | ||||
| time for the entire installation to be relocated.  The approach of | ||||
| makefile variable overrides for each directory variable is required by | ||||
| the GNU Coding Standards, and ideally causes no recompilation. | ||||
| However, some platforms have known limitations with the semantics of | ||||
| shared libraries that end up requiring recompilation when using this | ||||
| method, particularly noticeable in packages that use GNU Libtool. | ||||
|  | ||||
|    The second method involves providing the `DESTDIR' variable.  For | ||||
| example, `make install DESTDIR=/alternate/directory' will prepend | ||||
| `/alternate/directory' before all installation names.  The approach of | ||||
| `DESTDIR' overrides is not required by the GNU Coding Standards, and | ||||
| does not work on platforms that have drive letters.  On the other hand, | ||||
| it does better at avoiding recompilation issues, and works well even | ||||
| when some directory options were not specified in terms of `${prefix}' | ||||
| at `configure' time. | ||||
|  | ||||
| Optional Features | ||||
| ================= | ||||
|  | ||||
|    If the package supports it, you can cause programs to be installed | ||||
| with an extra prefix or suffix on their names by giving `configure' the | ||||
| option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. | ||||
|  | ||||
|    Some packages pay attention to `--enable-FEATURE' options to | ||||
| `configure', where FEATURE indicates an optional part of the package. | ||||
| They may also pay attention to `--with-PACKAGE' options, where PACKAGE | ||||
| is something like `gnu-as' or `x' (for the X Window System).  The | ||||
| `README' should mention any `--enable-' and `--with-' options that the | ||||
| package recognizes. | ||||
|  | ||||
|    For packages that use the X Window System, `configure' can usually | ||||
| find the X include and library files automatically, but if it doesn't, | ||||
| you can use the `configure' options `--x-includes=DIR' and | ||||
| `--x-libraries=DIR' to specify their locations. | ||||
|  | ||||
|    Some packages offer the ability to configure how verbose the | ||||
| execution of `make' will be.  For these packages, running `./configure | ||||
| --enable-silent-rules' sets the default to minimal output, which can be | ||||
| overridden with `make V=1'; while running `./configure | ||||
| --disable-silent-rules' sets the default to verbose, which can be | ||||
| overridden with `make V=0'. | ||||
|  | ||||
| Particular systems | ||||
| ================== | ||||
|  | ||||
|    On HP-UX, the default C compiler is not ANSI C compatible.  If GNU | ||||
| CC is not installed, it is recommended to use the following options in | ||||
| order to use an ANSI C compiler: | ||||
|  | ||||
|      ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" | ||||
|  | ||||
| and if that doesn't work, install pre-built binaries of GCC for HP-UX. | ||||
|  | ||||
|    On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot | ||||
| parse its `<wchar.h>' header file.  The option `-nodtk' can be used as | ||||
| a workaround.  If GNU CC is not installed, it is therefore recommended | ||||
| to try | ||||
|  | ||||
|      ./configure CC="cc" | ||||
|  | ||||
| and if that doesn't work, try | ||||
|  | ||||
|      ./configure CC="cc -nodtk" | ||||
|  | ||||
|    On Solaris, don't put `/usr/ucb' early in your `PATH'.  This | ||||
| directory contains several dysfunctional programs; working variants of | ||||
| these programs are available in `/usr/bin'.  So, if you need `/usr/ucb' | ||||
| in your `PATH', put it _after_ `/usr/bin'. | ||||
|  | ||||
|    On Haiku, software installed for all users goes in `/boot/common', | ||||
| not `/usr/local'.  It is recommended to use the following options: | ||||
|  | ||||
|      ./configure --prefix=/boot/common | ||||
|  | ||||
| Specifying the System Type | ||||
| ========================== | ||||
|  | ||||
|    There may be some features `configure' cannot figure out | ||||
| automatically, but needs to determine by the type of machine the package | ||||
| will run on.  Usually, assuming the package is built to be run on the | ||||
| _same_ architectures, `configure' can figure that out, but if it prints | ||||
| a message saying it cannot guess the machine type, give it the | ||||
| `--build=TYPE' option.  TYPE can either be a short name for the system | ||||
| type, such as `sun4', or a canonical name which has the form: | ||||
|  | ||||
|      CPU-COMPANY-SYSTEM | ||||
|  | ||||
| where SYSTEM can have one of these forms: | ||||
|  | ||||
|      OS | ||||
|      KERNEL-OS | ||||
|  | ||||
|    See the file `config.sub' for the possible values of each field.  If | ||||
| `config.sub' isn't included in this package, then this package doesn't | ||||
| need to know the machine type. | ||||
|  | ||||
|    If you are _building_ compiler tools for cross-compiling, you should | ||||
| use the option `--target=TYPE' to select the type of system they will | ||||
| produce code for. | ||||
|  | ||||
|    If you want to _use_ a cross compiler, that generates code for a | ||||
| platform different from the build platform, you should specify the | ||||
| "host" platform (i.e., that on which the generated programs will | ||||
| eventually be run) with `--host=TYPE'. | ||||
|  | ||||
| Sharing Defaults | ||||
| ================ | ||||
|  | ||||
|    If you want to set default values for `configure' scripts to share, | ||||
| you can create a site shell script called `config.site' that gives | ||||
| default values for variables like `CC', `cache_file', and `prefix'. | ||||
| `configure' looks for `PREFIX/share/config.site' if it exists, then | ||||
| `PREFIX/etc/config.site' if it exists.  Or, you can set the | ||||
| `CONFIG_SITE' environment variable to the location of the site script. | ||||
| A warning: not all `configure' scripts look for a site script. | ||||
|  | ||||
| Defining Variables | ||||
| ================== | ||||
|  | ||||
|    Variables not defined in a site shell script can be set in the | ||||
| environment passed to `configure'.  However, some packages may run | ||||
| configure again during the build, and the customized values of these | ||||
| variables may be lost.  In order to avoid this problem, you should set | ||||
| them in the `configure' command line, using `VAR=value'.  For example: | ||||
|  | ||||
|      ./configure CC=/usr/local2/bin/gcc | ||||
|  | ||||
| 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: | ||||
|  | ||||
|      CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash | ||||
|  | ||||
| `configure' Invocation | ||||
| ====================== | ||||
|  | ||||
|    `configure' recognizes the following options to control how it | ||||
| operates. | ||||
|  | ||||
| `--help' | ||||
| `-h' | ||||
|      Print a summary of all of the options to `configure', and exit. | ||||
|  | ||||
| `--help=short' | ||||
| `--help=recursive' | ||||
|      Print a summary of the options unique to this package's | ||||
|      `configure', and exit.  The `short' variant lists options used | ||||
|      only in the top level, while the `recursive' variant lists options | ||||
|      also present in any nested packages. | ||||
|  | ||||
| `--version' | ||||
| `-V' | ||||
|      Print the version of Autoconf used to generate the `configure' | ||||
|      script, and exit. | ||||
|  | ||||
| `--cache-file=FILE' | ||||
|      Enable the cache: use and save the results of the tests in FILE, | ||||
|      traditionally `config.cache'.  FILE defaults to `/dev/null' to | ||||
|      disable caching. | ||||
|  | ||||
| `--config-cache' | ||||
| `-C' | ||||
|      Alias for `--cache-file=config.cache'. | ||||
|  | ||||
| `--quiet' | ||||
| `--silent' | ||||
| `-q' | ||||
|      Do not print messages saying which checks are being made.  To | ||||
|      suppress all normal output, redirect it to `/dev/null' (any error | ||||
|      messages will still be shown). | ||||
|  | ||||
| `--srcdir=DIR' | ||||
|      Look for the package's source code in directory DIR.  Usually | ||||
|      `configure' can determine that directory automatically. | ||||
|  | ||||
| `--prefix=DIR' | ||||
|      Use DIR as the installation prefix.  *note Installation Names:: | ||||
|      for more details, including other options available for fine-tuning | ||||
|      the installation locations. | ||||
|  | ||||
| `--no-create' | ||||
| `-n' | ||||
|      Run the configure checks, but stop before creating any output | ||||
|      files. | ||||
|  | ||||
| `configure' also accepts some other, not widely useful, options.  Run | ||||
| `configure --help' for more details. | ||||
|  | ||||
							
								
								
									
										6
									
								
								Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| SUBDIRS = src tests | ||||
|  | ||||
| #EXTRA_DIST = LEGAL acinclude.m4 include | ||||
|  | ||||
| ACLOCAL_AMFLAGS = -I m4 | ||||
|  | ||||
							
								
								
									
										40
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								README
									
									
									
									
									
								
							| @@ -0,0 +1,40 @@ | ||||
|  | ||||
| 1. Generate private key | ||||
|  | ||||
| openssl genrsa -out privkey_evm.pem 1024 | ||||
|  | ||||
| 2. Generate public key | ||||
|  | ||||
| openssl rsa -pubout -in privkey_evm.pem -out pubkey_evm.pem | ||||
|  | ||||
| 3. Copy public (+private if to sign on device) key to the device/qemu /etc/keys | ||||
|  | ||||
| scp pubkey_evm.pem mad:/etc/keys | ||||
|  | ||||
| 4. Load keys and enable EVM | ||||
|  | ||||
| evm_enable.sh | ||||
|  | ||||
| This should be done at early phase, before mounting root filesystem. | ||||
|  | ||||
| 5. Sign EVM and use hash value for IMA - common case | ||||
|  | ||||
| evmctl sign --imahash test.txt | ||||
|  | ||||
| 6. Sign IMA and EVM - for immutable files and modules | ||||
|  | ||||
| evmctl sign --imasig test.txt | ||||
|  | ||||
| 7. Label whole filesystem | ||||
|  | ||||
| evm_label_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 '{}' \; | ||||
|  | ||||
| 8. Label filesystem in fix mode... | ||||
|  | ||||
| ima_fix_dir.sh <dir> | ||||
|  | ||||
|   | ||||
							
								
								
									
										14
									
								
								acinclude.m4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								acinclude.m4
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
|  | ||||
| AC_DEFUN([PKG_ARG_ENABLE], | ||||
| 	[ | ||||
| 	AC_MSG_CHECKING(whether to enable $1) | ||||
| 	AC_ARG_ENABLE([$1], AC_HELP_STRING([--enable-$1], [enable $1 (default is $2)]),  | ||||
| 	[pkg_cv_enable_$1=$enableval],	 | ||||
| 	[AC_CACHE_VAL([pkg_cv_enable_$1], [pkg_cv_enable_$1=$2])]) | ||||
| 	if test $pkg_cv_enable_$1 = yes; then | ||||
| 		AC_DEFINE([$3],, [$4]) | ||||
| 	fi | ||||
| 	AC_MSG_RESULT([$pkg_cv_enable_$1]) | ||||
| 	AM_CONDITIONAL($3, test $pkg_cv_enable_$1 = yes) | ||||
| ]) | ||||
|  | ||||
							
								
								
									
										16
									
								
								autogen.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								autogen.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #! /bin/sh | ||||
|  | ||||
| set -e | ||||
|  | ||||
| # new way | ||||
| # strange, but need this for Makefile.am, because it has -I m4 | ||||
| test -d m4 || mkdir m4 | ||||
| autoreconf -f -i | ||||
|  | ||||
| # old way | ||||
| #libtoolize --automake --copy --force | ||||
| #aclocal | ||||
| #autoconf --force | ||||
| #autoheader --force | ||||
| #automake --add-missing --copy --force-missing --gnu | ||||
|  | ||||
							
								
								
									
										73
									
								
								configure.ac
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								configure.ac
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | ||||
| # autoconf script | ||||
|  | ||||
| AC_PREREQ([2.65]) | ||||
| AC_INIT(evm-utils, 0.1, dmitry.kasatkin@intel.com) | ||||
| AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) | ||||
| AC_CONFIG_HEADERS([config.h]) | ||||
| AC_CONFIG_MACRO_DIR([m4]) | ||||
|   | ||||
| AC_CANONICAL_HOST | ||||
|  | ||||
| # Checks for programs. | ||||
| AC_PROG_CC | ||||
| AM_PROG_CC_C_O | ||||
| #AC_PROG_CXX | ||||
| #AC_PROG_CPP | ||||
| AC_PROG_INSTALL | ||||
| AC_PROG_LIBTOOL | ||||
| #AC_PROG_LN_S | ||||
| LT_INIT | ||||
|  | ||||
| # FIXME: Replace `main' with a function in `-lpthread': | ||||
| #AC_CHECK_LIB([pthread], [main]) | ||||
|  | ||||
| # Checks for header files. | ||||
| AC_HEADER_STDC | ||||
|  | ||||
| PKG_CHECK_MODULES(OPENSSL, [ openssl >= 0.9.8 ]) | ||||
| AC_SUBST(OPENSSL_CFLAGS) | ||||
| AC_SUBST(OPENSSL_LIBS) | ||||
| AC_CHECK_HEADER(unistd.h) | ||||
| AC_CHECK_HEADERS(openssl/conf.h) | ||||
|  | ||||
| AC_ARG_WITH(readline, [  --without-readline	without support funcy command editing for ncp]) | ||||
| if test "$with_readline" != "no"; then | ||||
| 	__LIBS="$LIBS" | ||||
| 	AC_CHECK_LIB(readline, readline) | ||||
| 	AC_CHECK_HEADERS(readline/readline.h,,  | ||||
| 		[AC_MSG_ERROR([readline header files not found.  | ||||
| 		Please, install libreadline for that. or use --without-readline])]) | ||||
| 	LIBS="$__LIBS" | ||||
| 	LDFLAGS_READLINE="-lreadline" | ||||
| fi | ||||
|  | ||||
| #debug support - yes for a while | ||||
| PKG_ARG_ENABLE(debug, "yes", DEBUG, [Enable Debug support]) | ||||
| if test $pkg_cv_enable_debug = yes; then | ||||
| 	CFLAGS="-g -O1 -Wall -Wstrict-prototypes -pipe" | ||||
| else | ||||
| 	CFLAGS="$CFLAGS -Wall -Wstrict-prototypes -pipe -fomit-frame-pointer" | ||||
| fi | ||||
|  | ||||
| # for gcov | ||||
| #CFLAGS="$CFLAGS -Wall -fprofile-arcs -ftest-coverage" | ||||
| #CXXFLAGS="$CXXFLAGS -Wall -fprofile-arcs -ftest-coverage" | ||||
| #LDFLAGS="$LDFLAGS -fprofile-arcs" | ||||
| #DISTCLEANFILES="*.gcno *.gcda" | ||||
|  | ||||
| AC_SUBST(LDFLAGS_READLINE) | ||||
|  | ||||
| AC_CONFIG_FILES([Makefile | ||||
| 		src/Makefile | ||||
| 		tests/Makefile | ||||
| 		evm-utils.spec | ||||
| 		]) | ||||
| AC_OUTPUT | ||||
|  | ||||
| # Give some feedback | ||||
| echo | ||||
| echo | ||||
| echo	"Configuration:"		 | ||||
| echo	"	debug:	$pkg_cv_enable_debug" | ||||
| echo | ||||
|  | ||||
							
								
								
									
										53
									
								
								evm-utils.spec.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								evm-utils.spec.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| Name:		@PACKAGE_NAME@ | ||||
| Version:	@PACKAGE_VERSION@ | ||||
| Release:	1%{?dist} | ||||
| Summary:	evm-utils - IMA/EVM support utilities | ||||
| Group:		System/Libraries | ||||
| License:	LGPLv2 | ||||
| #URL:		 | ||||
| Source0:	%{name}-%{version}.tar.gz | ||||
| BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root | ||||
|  | ||||
| BuildRequires:    autoconf | ||||
| BuildRequires:    automake | ||||
| BuildRequires:    openssl-devel | ||||
| BuildRequires:    libattr-devel | ||||
| BuildRequires:    readline-devel | ||||
| BuildRequires:    keyutils-libs-devel | ||||
|  | ||||
| %description | ||||
| This library provides EVM support utilities. | ||||
|  | ||||
| %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}/* | ||||
|  | ||||
| %changelog | ||||
| * Wed Jul 20 2011 Dmitry Kasatkin <dmitry.kasatkin@intel.com> | ||||
| - Initial package for MeeGo | ||||
|  | ||||
							
								
								
									
										12
									
								
								src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
|  | ||||
| bin_PROGRAMS = evmctl | ||||
|  | ||||
| evmctl_SOURCES = evmctl.c | ||||
| evmctl_CPPFLAGS = $(OPENSSL_CFLAGS) | ||||
| evmctl_LDFLAGS = $(LDFLAGS_READLINE) | ||||
| evmctl_LDADD =  $(OPENSSL_LIBS) -lkeyutils | ||||
|  | ||||
| INCLUDES = -I$(top_srcdir) -include config.h | ||||
|  | ||||
| DISTCLEANFILES = @DISTCLEANFILES@ | ||||
|  | ||||
							
								
								
									
										985
									
								
								src/evmctl.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										985
									
								
								src/evmctl.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,985 @@ | ||||
| /* | ||||
|  * evm-utils - IMA/EVM support utilities | ||||
|  * | ||||
|  * Copyright (C) 2011 Nokia Corporation | ||||
|  * Copyright (C) 2011 Intel Corporation | ||||
|  * | ||||
|  * Authors: | ||||
|  * Dmitry Kasatkin <dmitry.kasatkin@nokia.com> | ||||
|  *                 <dmitry.kasatkin@intel.com> | ||||
|  * | ||||
|  * This library is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public License | ||||
|  * version 2.1 as published by the Free Software Foundation. | ||||
|  * | ||||
|  * This library 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 | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with this library; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||||
|  * 02110-1301 USA | ||||
|  * | ||||
|  * File: evmctl.c | ||||
|  *	 IMA/EVM control program | ||||
|  */ | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/param.h> | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <stdint.h> | ||||
| #include <string.h> | ||||
| #include <attr/xattr.h> | ||||
| #include <getopt.h> | ||||
| #include <signal.h> | ||||
| #include <keyutils.h> | ||||
| #include <asm/byteorder.h> | ||||
| #include <syslog.h> | ||||
| #include <attr/xattr.h> | ||||
|  | ||||
| #ifdef HAVE_READLINE_READLINE_H | ||||
| #include <readline/readline.h> | ||||
| #include <readline/history.h> | ||||
| #endif | ||||
|  | ||||
| #include <openssl/sha.h> | ||||
| #include <openssl/sha.h> | ||||
| #include <openssl/rsa.h> | ||||
| #include <openssl/pem.h> | ||||
|  | ||||
| #define USE_FPRINTF | ||||
|  | ||||
| #ifdef USE_FPRINTF | ||||
| #define do_log(level, fmt, args...)	if (level <= verbose) fprintf(stderr, fmt, ##args) | ||||
| #define do_log_dump(level, p, len)	if (level <= verbose) do_dump(stderr, p, len) | ||||
| #else | ||||
| #define do_log(level, fmt, args...)	syslog(level, fmt, ##args) | ||||
| #define do_log_dump(p, len) | ||||
| #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) | ||||
| #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) | ||||
| #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 ": %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) | ||||
|  | ||||
| struct h_misc { | ||||
| 	unsigned long ino; | ||||
| 	uint32_t generation; | ||||
| 	uid_t uid; | ||||
| 	gid_t gid; | ||||
| 	unsigned short mode; | ||||
| } hmac_misc; | ||||
|  | ||||
| enum pubkey_algo { | ||||
| 	PUBKEY_ALGO_RSA, | ||||
| 	PUBKEY_ALGO_MAX, | ||||
| }; | ||||
|  | ||||
| enum digest_algo { | ||||
| 	DIGEST_ALGO_SHA1, | ||||
| 	DIGEST_ALGO_SHA256, | ||||
| 	DIGEST_ALGO_MAX | ||||
| }; | ||||
|  | ||||
| struct pubkey_hdr { | ||||
| 	uint8_t		version;	/* key format version */ | ||||
| 	time_t		timestamp;	/* key made, always 0 for now */ | ||||
| 	uint8_t		algo; | ||||
| 	uint8_t		nmpi; | ||||
| 	char		mpi[0]; | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
|  | ||||
| struct signature_hdr { | ||||
| 	uint8_t		version;	/* signature format version */ | ||||
| 	time_t		timestamp;	/* signature made */ | ||||
| 	uint8_t		algo; | ||||
| 	uint8_t		hash; | ||||
| 	uint8_t		keyid[8]; | ||||
| 	uint8_t		nmpi; | ||||
| 	char		mpi[0]; | ||||
| } __attribute__ ((packed)); | ||||
|  | ||||
|  | ||||
| static char *evm_config_xattrnames[] = { | ||||
| 	"security.selinux", | ||||
| 	"security.SMACK64", | ||||
| 	"security.ima", | ||||
| 	"security.capability", | ||||
| 	NULL | ||||
| }; | ||||
|  | ||||
| struct command { | ||||
| 	char	*name; | ||||
| 	int	(*func)(struct command *cmd); | ||||
| 	int	cmd; | ||||
| 	char	*arg; | ||||
| 	char	*msg;	/* extra info message */ | ||||
| }; | ||||
|  | ||||
| static int		verbose = LOG_INFO - 1; | ||||
| static int		g_argc; | ||||
| static char		**g_argv; | ||||
| static int		set_xattr = 1; | ||||
| static int		digest = 0; | ||||
| static int		digsig = 0; | ||||
| static char		*hash_algo = "sha1"; | ||||
| static int		binkey = 0; | ||||
|  | ||||
| extern struct command	cmds[]; | ||||
| static void print_usage(struct command *cmd); | ||||
|  | ||||
| static void do_dump(FILE *fp, const void *ptr, int len) | ||||
| { | ||||
|         int     i; | ||||
|         uint8_t *data = (uint8_t *)ptr; | ||||
|  | ||||
|         for (i = 0; i < len; i++) { | ||||
|                 fprintf(fp, "%02x", data[i]); | ||||
|         } | ||||
|         fprintf(fp, "\n"); | ||||
| } | ||||
|  | ||||
| static void dump(const void *ptr, int len) | ||||
| { | ||||
| 	do_dump(stdout, ptr, len); | ||||
| } | ||||
|  | ||||
| static inline 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 bin2file(const char *file, const char *ext, const unsigned char *data, int len) | ||||
| { | ||||
| 	FILE *fp; | ||||
| 	char name[strlen(file) + (ext ? strlen(ext) : 0) + 2]; | ||||
| 	int err; | ||||
| 	 | ||||
| 	if (ext) | ||||
| 		sprintf(name, "%s.%s", file, ext); | ||||
| 	else | ||||
| 		sprintf(name, "%s", file); | ||||
|  | ||||
| 	log_info("Writing to %s\n", name); | ||||
|  | ||||
| 	fp = fopen(name, "w"); | ||||
| 	if (!fp) { | ||||
| 		log_errno("Unable to open %s for writing", name); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	err = fwrite(data, len, 1, fp); | ||||
| 	fclose(fp); | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| static char *file2bin(const char *file, int *size) | ||||
| { | ||||
| 	FILE *fp; | ||||
| 	int len; | ||||
| 	char *data; | ||||
| 		 | ||||
| 	len = get_filesize(file); | ||||
| 	fp = fopen(file, "r"); | ||||
| 	if (!fp) { | ||||
| 		log_errno("Unable to open %s", file); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	data = malloc(len); | ||||
| 	if (!fread(data, len, 1, fp)) | ||||
| 		len = 0; | ||||
| 	fclose(fp); | ||||
| 	 | ||||
| 	*size = len; | ||||
| 	return data;	 | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Create binary key representation suitable for kernel | ||||
|  */ | ||||
| static int key2bin(RSA *key, unsigned char *pub) | ||||
| { | ||||
| 	int len, b, offset = 0; | ||||
| 	struct pubkey_hdr *pkh = (struct pubkey_hdr *)pub; | ||||
|  | ||||
| 	/* add key header */ | ||||
| 	pkh->version = 1; | ||||
| 	pkh->timestamp = 0;	/* PEM has no timestamp?? */ | ||||
| 	pkh->algo = PUBKEY_ALGO_RSA; | ||||
| 	pkh->nmpi = 2; | ||||
| 	 | ||||
| 	offset += sizeof(*pkh); | ||||
| 	 | ||||
| 	// MPIs | ||||
| 	len = BN_num_bytes(key->n); | ||||
| 	b = BN_num_bits(key->n); | ||||
| 	pub[offset++] = b >> 8; | ||||
| 	pub[offset++] = b & 0xff; | ||||
| 	BN_bn2bin(key->n, &pub[offset]); | ||||
| 	offset += len; | ||||
| 	 | ||||
| 	len = BN_num_bytes(key->e); | ||||
| 	b = BN_num_bits(key->e); | ||||
| 	pub[offset++] = b >> 8; | ||||
| 	pub[offset++] = b & 0xff; | ||||
| 	BN_bn2bin(key->e, &pub[offset]); | ||||
| 	offset += len; | ||||
| 	 | ||||
| 	return offset; | ||||
| } | ||||
|  | ||||
| static int read_key(const char *inkey, unsigned char *pub) | ||||
| { | ||||
| 	FILE *fp; | ||||
| 	RSA *key = NULL, *key1; | ||||
| 	int len; | ||||
|  | ||||
| 	fp = fopen(inkey, "r"); | ||||
| 	if (!fp) { | ||||
| 		log_errno("read key failed from file %s", inkey); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	key1 = PEM_read_RSA_PUBKEY(fp, &key, NULL, NULL); | ||||
| 	fclose(fp); | ||||
| 	if (!key1) { | ||||
| 		log_errno("PEM_read_RSA_PUBKEY() failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	len = key2bin(key, pub); | ||||
| 	 | ||||
| 	RSA_free(key); | ||||
| 	 | ||||
| 	return len; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void calc_keyid(uint8_t *keyid, char *str, const unsigned char *pkey, int len) | ||||
| { | ||||
| 	uint8_t sha1[SHA_DIGEST_LENGTH]; | ||||
| 	uint64_t id; | ||||
| 	 | ||||
| 	log_debug("pkey:\n"); | ||||
| 	log_debug_dump(pkey, len); | ||||
| 	SHA1(pkey, len, sha1);	 | ||||
| 	 | ||||
| 	//sha1[12 - 19] is exactly keyid from gpg file | ||||
| 	memcpy(keyid, sha1 + 12, 8); | ||||
| 	log_debug("keyid:\n"); | ||||
| 	log_debug_dump(keyid, 8); | ||||
| 	 | ||||
| 	id = __be64_to_cpup((uint64_t *)keyid); | ||||
| 	sprintf(str, "%llX", id); | ||||
| 	log_info("keyid: %s\n", str);	 | ||||
| } | ||||
|  | ||||
| static int sign_hash(const unsigned char *hash, int size, const char *keyfile, unsigned char *sig) | ||||
| { | ||||
| 	int err, len; | ||||
| 	SHA_CTX ctx; | ||||
| 	unsigned char pub[1024]; | ||||
| 	RSA *key = NULL, *key1; | ||||
| 	FILE *fp; | ||||
| 	char name[20]; | ||||
| 	unsigned char sighash[20]; | ||||
| 	struct signature_hdr *hdr = (struct signature_hdr *)sig; | ||||
| 	uint16_t *blen; | ||||
| 	 | ||||
| 	log_info("hash: "); | ||||
| 	log_dump(hash, size); | ||||
| 	 | ||||
| 	fp = fopen(keyfile, "r");	 | ||||
| 	if (!fp) { | ||||
| 		log_errno("Unable to open keyfile %s", keyfile); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	key1 = PEM_read_RSAPrivateKey(fp, &key, NULL, NULL); | ||||
| 	fclose(fp); | ||||
| 	if (!key1) { | ||||
| 		log_errno("RSAPrivateKey() failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* now create a new hash */ | ||||
| 	hdr->version = 1; | ||||
| 	time(&hdr->timestamp); | ||||
| 	hdr->algo = PUBKEY_ALGO_RSA; | ||||
| 	hdr->hash = DIGEST_ALGO_SHA1; | ||||
| 	 | ||||
| 	len = key2bin(key, pub); | ||||
| 	calc_keyid(hdr->keyid, name, pub, len); | ||||
| 	 | ||||
| 	hdr->nmpi = 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_private_encrypt(sizeof(sighash), sighash, sig + sizeof(*hdr) + 2, key, RSA_PKCS1_PADDING); | ||||
| 	RSA_free(key); | ||||
| 	if (err < 0) { | ||||
| 		log_errno("RSA_private_encrypt() failed: %d", err); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	len = err; | ||||
| 	 | ||||
| 	/* we add bit length of the signature to make it gnupg compatible */ | ||||
| 	blen = (uint16_t *)(sig + sizeof(*hdr)); | ||||
| 	*blen = __cpu_to_be16(len << 3); | ||||
| 	len += sizeof(*hdr) + 2; | ||||
| 	log_info("evm/ima signature: %d bytes\n", len); | ||||
| 	if (!set_xattr || verbose >= LOG_INFO) | ||||
| 		dump(sig, len); | ||||
|  | ||||
| 	return len;	 | ||||
| } | ||||
|  | ||||
| static int calc_evm_hash(const char *file, const char *keyfile, unsigned char *hash) | ||||
| { | ||||
| 	struct stat st; | ||||
| 	int fd, err, len; | ||||
| 	uint32_t generation; | ||||
| 	SHA_CTX ctx; | ||||
| 	char **xattrname; | ||||
| 	char xattr_value[1024]; | ||||
| 	 | ||||
| 	fd = open(file, 0); | ||||
| 	if (fd < 0) { | ||||
| 		log_errno("Unable to open %s", file); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	if (fstat(fd, &st)) { | ||||
| 		log_errno("fstat() failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	len = st.st_size; | ||||
| 	 | ||||
| 	if (ioctl(fd, EXT34_IOC_GETVERSION, &generation)) { | ||||
| 		log_errno("ioctl() failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	close(fd); | ||||
| 	 | ||||
| 	log_info("generation: %u\n", generation); | ||||
|  | ||||
| 	SHA1_Init(&ctx); | ||||
|  | ||||
| 	for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { | ||||
| 		err = getxattr(file, *xattrname, xattr_value, sizeof(xattr_value)); | ||||
| 		if (err < 0) { | ||||
| 			log_info("no attr: %s\n", *xattrname); | ||||
| 			continue; | ||||
| 		} | ||||
| 		//log_debug("name: %s, value: %s, size: %d\n", *xattrname, xattr_value, err); | ||||
| 		log_info("name: %s, size: %d\n", *xattrname, err); | ||||
| 		log_debug_dump(xattr_value, err); | ||||
| 		SHA1_Update(&ctx, xattr_value, err); | ||||
| 	} | ||||
|  | ||||
| 	memset(&hmac_misc, 0, sizeof(hmac_misc)); | ||||
| 	hmac_misc.ino = st.st_ino; | ||||
| 	hmac_misc.generation = generation; | ||||
| 	hmac_misc.uid = st.st_uid; | ||||
| 	hmac_misc.gid = st.st_gid; | ||||
| 	hmac_misc.mode = st.st_mode; | ||||
| 	 | ||||
| 	SHA1_Update(&ctx, (const unsigned char*)&hmac_misc, sizeof(hmac_misc)); | ||||
| 	SHA1_Final(hash, &ctx); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int sign_evm(const char *file, const char *key) | ||||
| { | ||||
| 	unsigned char hash[20]; | ||||
| 	unsigned char sig[1024] = "\x03"; | ||||
| 	int err; | ||||
|  | ||||
| 	calc_evm_hash(file, key, hash); | ||||
| 	 | ||||
| 	err = sign_hash(hash, sizeof(hash), key, sig + 1); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	 | ||||
| 	if (set_xattr) { | ||||
| 		err = setxattr(file, "security.evm", sig, err + 1, 0); | ||||
| 		if (err < 0) { | ||||
| 			log_errno("setxattr failed: %s", file); | ||||
| 			return err; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int calc_file_hash(const char *file, uint8_t *hash) | ||||
| { | ||||
| 	EVP_MD_CTX ctx; | ||||
| 	const EVP_MD *md; | ||||
| 	uint8_t	*data; | ||||
| 	int err, size, bs = DATA_SIZE; | ||||
| 	size_t len, mdlen; | ||||
| 	FILE *fp; | ||||
|  | ||||
| 	data = malloc(bs); | ||||
| 	if (!data) { | ||||
| 		log_errno("malloc failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 		 | ||||
| 	fp = fopen(file, "r"); | ||||
| 	if (!fp) { | ||||
| 		log_errno("Unable to open %s", file); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	OpenSSL_add_all_digests(); | ||||
|  | ||||
| 	md = EVP_get_digestbyname(hash_algo); | ||||
| 	if (!md) { | ||||
| 		log_errno("EVP_get_digestbyname() failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	err = EVP_DigestInit(&ctx, md); | ||||
| 	if (!err) { | ||||
| 		log_errno("EVP_DigestInit() failed"); | ||||
| 		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_errno("fread() error\n"); | ||||
| 				return -1; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		err = EVP_DigestUpdate(&ctx, data, len); | ||||
| 		if (!err) { | ||||
| 			log_errno("EVP_DigestUpdate() failed"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	err = EVP_DigestFinal(&ctx, hash, &mdlen); | ||||
| 	if (!err) { | ||||
| 		log_errno("EVP_DigestFinal() failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	fclose(fp); | ||||
| 	 | ||||
| 	free(data); | ||||
| 	 | ||||
| 	return mdlen; | ||||
| } | ||||
|  | ||||
| static int hash_ima(const char *file) | ||||
| { | ||||
| 	unsigned char hash[65] = "\x01";// MAX hash size + 1 | ||||
| 	int err; | ||||
|  | ||||
| 	err = calc_file_hash(file, hash + 1); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	 | ||||
| 	if (!set_xattr || verbose >= LOG_INFO) | ||||
| 		dump(hash, err + 1); | ||||
|  | ||||
| 	if (set_xattr) { | ||||
| 		err = setxattr(file, "security.ima", hash, err + 1, 0); | ||||
| 		if (err < 0) { | ||||
| 			log_errno("setxattr failed: %s", file); | ||||
| 			return err; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int cmd_hash_ima(struct command *cmd) | ||||
| { | ||||
| 	char *file = g_argv[optind++]; | ||||
|  | ||||
| 	if (!file) { | ||||
| 		log_err("Parameters missing\n"); | ||||
| 		print_usage(cmd); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	 | ||||
| 	return hash_ima(file); | ||||
| } | ||||
|  | ||||
| static int sign_ima(const char *file, const char *key) | ||||
| { | ||||
| 	unsigned char hash[64]; | ||||
| 	unsigned char sig[1024] = "\x03"; | ||||
| 	int err; | ||||
| 	 | ||||
| 	err = calc_file_hash(file, hash); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	 | ||||
| 	err = sign_hash(hash, err, key, sig + 1); | ||||
| 	if (err < 0) | ||||
| 		return err; | ||||
| 	 | ||||
| 	if (set_xattr) { | ||||
| 		err = setxattr(file, "security.ima", sig, err + 1, 0); | ||||
| 		if (err < 0) { | ||||
| 			log_errno("setxattr failed: %s", file); | ||||
| 			return err; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int cmd_sign_ima(struct command *cmd) | ||||
| { | ||||
| 	char *key, *file = g_argv[optind++]; | ||||
| 	 | ||||
| 	if (!file) { | ||||
| 		log_err("Parameters missing\n"); | ||||
| 		print_usage(cmd); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	 | ||||
| 	key = g_argv[optind++]; | ||||
| 	if (!key) | ||||
| 		key = "/etc/keys/privkey_evm.pem"; | ||||
| 	 | ||||
| 	return sign_ima(file, key); | ||||
| 	 | ||||
| } | ||||
|  | ||||
| static int cmd_sign_evm(struct command *cmd) | ||||
| { | ||||
| 	char *key, *file = g_argv[optind++]; | ||||
| 	int err; | ||||
| 	 | ||||
| 	if (!file) { | ||||
| 		log_err("Parameters missing\n"); | ||||
| 		print_usage(cmd); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	 | ||||
| 	key = g_argv[optind++]; | ||||
| 	if (!key) | ||||
| 		key = "/etc/keys/privkey_evm.pem"; | ||||
| 	 | ||||
| 	if (digsig) { | ||||
| 		err = sign_ima(file, key); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 	} | ||||
| 	 | ||||
| 	if (digest) { | ||||
| 		err = hash_ima(file); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 	} | ||||
| 	 | ||||
| 	return sign_evm(file, key); | ||||
| } | ||||
|  | ||||
| static int verify_hash(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 = NULL, *key1; | ||||
| 	FILE *fp; | ||||
| 	unsigned char sighash[20]; | ||||
| 	struct signature_hdr *hdr = (struct signature_hdr *)sig; | ||||
| 	 | ||||
| 	log_info("hash: "); | ||||
| 	log_dump(hash, size); | ||||
| 	 | ||||
| 	fp = fopen(keyfile, "r");	 | ||||
| 	if (!fp) { | ||||
| 		log_errno("Unable to open keyfile %s", keyfile); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	key1 = PEM_read_RSA_PUBKEY(fp, &key, NULL, NULL); | ||||
| 	fclose(fp); | ||||
| 	if (!key1) { | ||||
| 		log_errno("PEM_read_RSA_PUBKEY() failed"); | ||||
| 		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_errno("RSA_public_decrypt() failed: %d", err); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	len = err; | ||||
| 	 | ||||
| 	if (len != sizeof(sighash) || memcmp(out, sighash, len) != 0) { | ||||
| 		log_errno("Verification failed: %d", err); | ||||
| 		return -1; | ||||
| 	} else { | ||||
| 		//log_info("Verification is OK\n"); | ||||
| 		printf("Verification is OK\n"); | ||||
| 	} | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int verify_evm(const char *file, const char *key) | ||||
| { | ||||
| 	unsigned char hash[20]; | ||||
| 	unsigned char sig[1024]; | ||||
| 	int err; | ||||
|  | ||||
| 	calc_evm_hash(file, key, hash); | ||||
| 	 | ||||
| 	err = getxattr(file, "security.evm", sig, sizeof(sig)); | ||||
| 	if (err < 0) { | ||||
| 		log_errno("getxattr failed"); | ||||
| 		return err; | ||||
| 	} | ||||
| 	 | ||||
| 	if (sig[0] != 0x03) { | ||||
| 		log_errno("security.evm has not signature"); | ||||
| 		return err; | ||||
| 	} | ||||
| 	 | ||||
| 	return verify_hash(hash, sizeof(hash), sig + 1, err - 1, key); | ||||
| } | ||||
|  | ||||
| static int cmd_verify_evm(struct command *cmd) | ||||
| { | ||||
| 	char *key, *file = g_argv[optind++]; | ||||
| 	 | ||||
| 	if (!file) { | ||||
| 		log_err("Parameters missing\n"); | ||||
| 		print_usage(cmd); | ||||
| 		return 1; | ||||
| 	} | ||||
| 	 | ||||
| 	key = g_argv[optind++]; | ||||
| 	if (!key) | ||||
| 		key = "/etc/keys/pubkey_evm.pem"; | ||||
| 	 | ||||
| 	return verify_evm(file, key); | ||||
| } | ||||
|  | ||||
| static int cmd_convert(struct command *cmd) | ||||
| { | ||||
| 	char *inkey, *outkey = NULL; | ||||
| 	unsigned char pub[1024]; | ||||
| 	char name[20]; | ||||
| 	int len; | ||||
| 	uint8_t keyid[8]; | ||||
| 	 | ||||
| 	inkey = g_argv[optind++]; | ||||
| 	if (!inkey) | ||||
| 		inkey = "/etc/keys/pubkey_evm.pem"; | ||||
| 	else | ||||
| 		outkey = g_argv[optind++]; | ||||
| 		 | ||||
| 	if (!outkey) | ||||
| 		outkey = "pubkey_evm.bin"; | ||||
|  | ||||
| 	log_info("Convert public key %s to %s\n", inkey, outkey);	 | ||||
|  | ||||
| 	len = read_key(inkey, pub); | ||||
| 	if (len < 0) | ||||
| 		return -1; | ||||
| 	 | ||||
| 	calc_keyid(keyid, name, pub, len); | ||||
| 	 | ||||
| 	bin2file(outkey, name, pub, len); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int cmd_import_bin(struct command *cmd) | ||||
| { | ||||
| 	int len; | ||||
| 	char *inkey, *ring = NULL; | ||||
| 	char *key, name[20]; | ||||
| 	key_serial_t id; | ||||
| 	uint8_t keyid[8]; | ||||
| 	 | ||||
| 	inkey = g_argv[optind++]; | ||||
| 	if (!inkey) | ||||
| 		inkey = "/etc/keys/pubkey_evm.bin"; | ||||
|  	else | ||||
|  		ring = g_argv[optind++]; | ||||
|  		 | ||||
|  	if (!ring) | ||||
|  		id = KEY_SPEC_USER_KEYRING; | ||||
| 	else | ||||
| 		id = atoi(ring); | ||||
|  | ||||
| 	key = file2bin(inkey, &len); | ||||
| 	if (!key) | ||||
| 		return -1; | ||||
| 	 | ||||
| 	calc_keyid(keyid, name, (unsigned char *)key, len); | ||||
|  | ||||
|  	log_info("Importing public key %s from file %s into keyring %d\n", name, inkey, id); | ||||
| 	 | ||||
| 	id = add_key("user", name, key, len, id); | ||||
| 	if (id < 0) { | ||||
| 		log_errno("add_key failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	log_info("keyid: %d\n", id); | ||||
| 	printf("%d\n", id); | ||||
| 	 | ||||
| 	free(key); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int cmd_import(struct command *cmd) | ||||
| { | ||||
| 	char *inkey, *ring = NULL; | ||||
| 	unsigned char key[1024]; | ||||
| 	int id, len; | ||||
| 	char name[20]; | ||||
| 	uint8_t keyid[8]; | ||||
|  | ||||
| 	if (binkey) | ||||
| 		return cmd_import_bin(cmd); | ||||
| 	 | ||||
| 	inkey = g_argv[optind++]; | ||||
| 	if (!inkey) | ||||
| 		inkey = "/etc/keys/pubkey_evm.pem"; | ||||
|  	else | ||||
|  		ring = g_argv[optind++]; | ||||
|  		 | ||||
|  	if (!ring) | ||||
|  		id = KEY_SPEC_USER_KEYRING; | ||||
| 	else | ||||
| 		id = atoi(ring); | ||||
|  | ||||
| 	len = read_key(inkey, key); | ||||
| 	if (len < 0) | ||||
| 		return -1; | ||||
| 	 | ||||
| 	calc_keyid(keyid, name, key, len); | ||||
| 	 | ||||
|  	log_info("Importing public key %s from file %s into keyring %d\n", name, inkey, id); | ||||
| 	 | ||||
| 	id = add_key("user", name, key, len, id); | ||||
| 	if (id < 0) { | ||||
| 		log_errno("add_key failed"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	log_info("keyid: %d\n", id); | ||||
| 	printf("%d\n", id); | ||||
| 	 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void print_usage(struct command *cmd) | ||||
| { | ||||
| 	printf("usage: %s %s\n", cmd->name, cmd->arg ? cmd->arg : ""); | ||||
| } | ||||
|  | ||||
| static void print_full_usage(struct command *cmd) | ||||
| { | ||||
| 	if (cmd->name) | ||||
| 		printf("usage: %s %s\n", cmd->name, cmd->arg ? cmd->arg : ""); | ||||
| 	if (cmd->msg) | ||||
| 		printf("description:\n%s", cmd->msg); | ||||
|  | ||||
| } | ||||
|  | ||||
| static int print_command_usage(struct command *cmds, char *command) | ||||
| { | ||||
| 	struct command	*cmd; | ||||
| 	struct command	nullcmd = {NULL, NULL, 0, NULL, NULL}; | ||||
|  | ||||
| 	for (cmd = cmds; memcmp(cmd, &nullcmd, sizeof(nullcmd)) != 0; cmd++) { | ||||
| 		if (cmd->name) | ||||
| 			if (strcmp(cmd->name, command) == 0) { | ||||
| 				print_full_usage(cmd); | ||||
| 				return 0; | ||||
| 			} | ||||
| 	} | ||||
| 	printf("invalid command: %s\n", command); | ||||
| 	return 	1; | ||||
| } | ||||
|  | ||||
| static void print_all_usage(struct command *cmds) | ||||
| { | ||||
| 	struct command	*cmd; | ||||
| 	struct command	nullcmd = {NULL, NULL, 0, NULL, NULL}; | ||||
| 	 | ||||
| 	for (cmd = cmds; memcmp(cmd, &nullcmd, sizeof(nullcmd)) != 0; cmd++) { | ||||
| 		if (cmd->name && cmd->arg) | ||||
| 			printf("%s %s\n", cmd->name, cmd->arg); | ||||
| 		else if (cmd->msg) | ||||
| 			printf("%s", cmd->msg); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int call_command(struct command *cmds, char *command) | ||||
| { | ||||
| 	struct command	*cmd; | ||||
| 	struct command	nullcmd = {NULL, NULL, 0, NULL, NULL}; | ||||
| 	 | ||||
| 	for (cmd = cmds; memcmp(cmd, &nullcmd, sizeof(nullcmd)) != 0; cmd++) { | ||||
| 		if (cmd->name && strcasecmp(cmd->name, command) == 0) { | ||||
| 			return cmd->func(cmd); | ||||
| 		} | ||||
| 	} | ||||
| 	printf("Invalid command: %s\n", command); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| static int cmd_help(struct command *cmd) | ||||
| { | ||||
| 	if (!g_argv[optind]) { | ||||
| 		print_usage(cmd); | ||||
| 		return 0; | ||||
| 	} else | ||||
| 		return print_command_usage(cmds, g_argv[optind]); | ||||
| } | ||||
|  | ||||
| static void usage(void) | ||||
| { | ||||
| 	printf("Usage: evmctl <command> [parameters..]\n"); | ||||
|  | ||||
| 	print_all_usage(cmds); | ||||
| } | ||||
|  | ||||
| struct command cmds[] = { | ||||
| 	{"help", cmd_help, 0, "<command>"}, | ||||
| 	{"import", cmd_import, 0, "[--bin] inkey keyring", "Import public key (PEM/bin) into the keyring.\n" }, | ||||
| 	{"convert", cmd_convert, 0, "inkey outkey", "Convert PEM public key into IMA/EVM kernel friendly format.\n" }, | ||||
| 	{"sign", cmd_sign_evm, 0, "[--imahash | --imasig ] file [key]", "Sign file metadata.\n" }, | ||||
| 	{"verify", cmd_verify_evm, 0, "file", "Verify EVM.\n" }, | ||||
| 	{"ima_sign", cmd_sign_ima, 0, "file [key]", "Sign file content.\n" }, | ||||
| 	{"ima_hash", cmd_hash_ima, 0, "file", "Hash file content.\n" }, | ||||
| 	{0, 0, 0, NULL} | ||||
| }; | ||||
|  | ||||
| static struct option  opts[] = { | ||||
| 	{"help", 0, 0, 'h'}, | ||||
| 	{"inkey", 1, 0, 'k'}, | ||||
| 	{"imasig", 0, 0, 's'}, | ||||
| 	{"imahash", 0, 0, 'd'}, | ||||
| 	{"hashalgo", 1, 0, 'a'}, | ||||
| 	{"bin", 0, 0, 'b'}, | ||||
| 	{} | ||||
|  | ||||
| }; | ||||
|  | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	int err = 0, c, lind; | ||||
|  | ||||
| 	g_argv = argv; | ||||
| 	g_argc = argc; | ||||
|  | ||||
| 	while (1) { | ||||
| 		c = getopt_long(argc, argv, "hk:vnsda:b", opts, &lind); | ||||
| 		if (c == -1) | ||||
| 			break; | ||||
| 			 | ||||
| 		switch (c) { | ||||
| 		case 'h': | ||||
| 			usage(); | ||||
| 			exit(0); | ||||
| 			break; | ||||
| 		case 'k': | ||||
| 			printf("inkey: %s\n", optarg); | ||||
| 			break; | ||||
| 		case 'v': | ||||
| 			verbose++; | ||||
| 			break; | ||||
| 		case 'd': | ||||
| 			digest = 1; | ||||
| 			break; | ||||
| 		case 's': | ||||
| 			digsig = 1; | ||||
| 			break; | ||||
| 		case 'n': | ||||
| 			set_xattr = 0; // do not set Extended Attributes... just print signature | ||||
| 			break; | ||||
| 		case 'a': | ||||
| 			hash_algo = optarg; | ||||
| 			break; | ||||
| 		case 'b': | ||||
| 			binkey = 1; | ||||
| 			break; | ||||
| 		case '?': | ||||
| 			exit(1); | ||||
| 			break; | ||||
| 		default: | ||||
| 			log_err("getopt() returned: %d (%c)\n", c, c); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (argv[optind] == NULL) | ||||
| 		usage(); | ||||
| 	else | ||||
| 		err = call_command(cmds, argv[optind++]); | ||||
|  | ||||
| 	return err; | ||||
| } | ||||
							
								
								
									
										6
									
								
								tests/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								tests/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| pkglib_PROGRAMS = openclose | ||||
|  | ||||
| openclose_SOURCES = openclose.c | ||||
|  | ||||
| dist_pkglib_SCRIPTS = evm_enable.sh evm_genkey.sh evm_label_all.sh sign_modules_dir.sh ima_fix_dir.sh | ||||
|  | ||||
							
								
								
									
										25
									
								
								tests/evm_enable.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										25
									
								
								tests/evm_enable.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #!/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 | ||||
|  | ||||
							
								
								
									
										8
									
								
								tests/evm_genkey.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								tests/evm_genkey.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #!/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 | ||||
|  | ||||
							
								
								
									
										17
									
								
								tests/evm_label_all.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								tests/evm_label_all.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/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 \) ! -path "/lib/modules/*" -type f -uid 0 -exec evmctl sign --imahash $verbose '{}' \; | ||||
| find /lib/modules ! -name "*.ko" -type f -uid 0 -exec evmctl sign --imahash $verbose '{}' \; | ||||
| # security.ima needs to have signature for modules | ||||
| find /lib/modules -name "*.ko" -type f -uid 0 -exec evmctl sign --imasig $verbose '{}' \; | ||||
|  | ||||
							
								
								
									
										8
									
								
								tests/ima_fix_dir.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								tests/ima_fix_dir.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| dir=${1:-/} | ||||
|  | ||||
| echo "Fixing dir: $dir" | ||||
|  | ||||
| find $dir \( -fstype rootfs -o -fstype ext3 -o -fstype ext4 \) -type f -uid 0 -exec openclose '{}' \; | ||||
|  | ||||
							
								
								
									
										20
									
								
								tests/openclose.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/openclose.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #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; | ||||
| } | ||||
|  | ||||
							
								
								
									
										15
									
								
								tests/sign_modules_dir.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								tests/sign_modules_dir.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| #!/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 -uid 0 -exec evmctl sign --imasig '{}' \; | ||||
| find $dir ! -name "*.ko" -type f -uid 0 -exec evmctl sign --imahash '{}' \; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Dmitry Kasatkin
					Dmitry Kasatkin