Merge branch 'master' of https://git.savannah.gnu.org/git/grub into gfxmenu/time
This commit is contained in:
commit
0482ab6010
3
.gitignore
vendored
3
.gitignore
vendored
@ -249,8 +249,6 @@ widthspec.bin
|
||||
/pata_test
|
||||
/po/*.gmo
|
||||
/po/*.mo
|
||||
/po/*.po
|
||||
/po/LINGUAS
|
||||
/po/Makefile.in.in
|
||||
/po/Makevars
|
||||
/po/Makevars.template
|
||||
@ -283,3 +281,4 @@ widthspec.bin
|
||||
/xfs_test
|
||||
/xzcompress_test
|
||||
/zfs_test
|
||||
/zfs_zstd_test
|
||||
|
||||
8
BUGS
8
BUGS
@ -1,7 +1,3 @@
|
||||
GRUB team is aware of following problems:
|
||||
- Currently search and assembling multidevice abstractions scans
|
||||
all the devices which can be slow.
|
||||
- Cache isn't used correctly for video which results in slowness.
|
||||
Open bugs and issues are captured in the GRUB bug tracking system:
|
||||
|
||||
While these are bugs their solution has a potential of breaking more and more
|
||||
seriously. So it was decided for 1.99 that they aren't fixed.
|
||||
https://savannah.gnu.org/bugs/?group=grub
|
||||
|
||||
39
INSTALL
39
INSTALL
@ -25,6 +25,7 @@ configuring the GRUB.
|
||||
* Flex 2.5.35 or later
|
||||
* pkg-config
|
||||
* GNU patch
|
||||
* wget (for downloading updated translations)
|
||||
* Other standard GNU/Unix tools
|
||||
* a libc with large file support (e.g. glibc 2.1 or later)
|
||||
|
||||
@ -45,12 +46,17 @@ To build GRUB's graphical terminal (gfxterm), you need:
|
||||
To build grub-mkfont the unicode fonts are required (xfonts-unifont package
|
||||
on Debian).
|
||||
|
||||
To build the optional grub-protect utility the following is needed:
|
||||
|
||||
* libtasn1 (libtasn1-6-dev on Debian)
|
||||
|
||||
If you use a development snapshot or want to hack on GRUB you may
|
||||
need the following.
|
||||
|
||||
* Python 3 (NOTE: python 2.6 should still work, but it's not tested)
|
||||
* Autoconf 2.64 or later
|
||||
* Automake 1.14 or later
|
||||
* GNU Autoconf Archive (autoconf-archive on Debian)
|
||||
|
||||
Your distro may package cross-compiling toolchains such as the following
|
||||
incomplete list on Debian: gcc-aarch64-linux-gnu, gcc-arm-linux-gnueabihf,
|
||||
@ -62,7 +68,7 @@ More cross compiling toolchains can be found at the following trusted sites:
|
||||
* https://mirrors.kernel.org/pub/tools/crosstool/
|
||||
* https://toolchains.bootlin.com/
|
||||
|
||||
Prerequisites for make-check:
|
||||
Prerequisites for running make-check successfully:
|
||||
|
||||
* qemu, specifically the binary "qemu-system-ARCH" where ARCH is the
|
||||
architecture GRUB has been built for; the "qemu-system" package on Debian
|
||||
@ -82,6 +88,8 @@ Prerequisites for make-check:
|
||||
reiserfs, udf, xfs
|
||||
- On newer kernels, the exfat kernel modules may be used instead of the
|
||||
exfat FUSE filesystem
|
||||
- Kernel version 6.12.x was the last series to include reiserfs support,
|
||||
so later kernels will fail the reiser filesystem test.
|
||||
* The following are Debian named packages required mostly for the full
|
||||
suite of filesystem testing (but some are needed by other tests as well):
|
||||
- btrfs-progs, dosfstools, e2fsprogs, erofs-utils, exfatprogs, exfat-fuse,
|
||||
@ -92,8 +100,8 @@ Prerequisites for make-check:
|
||||
- attr, cpio, g++, gawk, parted, recode, tar, util-linux
|
||||
|
||||
Note that `make check' will run and many tests may complete successfully
|
||||
with only a subset of these prerequisites. However, some tests may be
|
||||
skipped or fail due to missing prerequisites.
|
||||
with only a subset of these prerequisites. However, some tests may fail
|
||||
due to missing prerequisites.
|
||||
|
||||
To build the documentation you'll need:
|
||||
* texinfo, for the info and html documentation
|
||||
@ -136,15 +144,12 @@ The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code.
|
||||
|
||||
2. Skip this and following step if you use release tarball and proceed to
|
||||
step 4. If you want translations type `./linguas.sh'.
|
||||
|
||||
3. Type `./bootstrap'.
|
||||
2. Type `./bootstrap'.
|
||||
|
||||
The autogen.sh (called by bootstrap) uses python. By default autodetect
|
||||
it, but it can be overridden by setting the PYTHON variable.
|
||||
The autogen.sh (called by bootstrap) uses python. By default it is
|
||||
autodetected, but it can be overridden by setting the PYTHON variable.
|
||||
|
||||
4. Type `./configure' to configure the package for your system.
|
||||
3. Type `./configure' to configure the package for your system.
|
||||
If you're using `csh' on an old version of System V, you might
|
||||
need to type `sh ./configure' instead to prevent `csh' from trying
|
||||
to execute `configure' itself.
|
||||
@ -152,19 +157,19 @@ The simplest way to compile this package is:
|
||||
Running `configure' takes awhile. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
6. Type `make' to compile the package.
|
||||
4. Type `make' to compile the package.
|
||||
|
||||
7. Optionally, type `make check' to run any self-tests that come with
|
||||
the package. Note that many of the tests require root privileges in
|
||||
order to run.
|
||||
5. Optionally, type `make check' to run any self-tests that come with
|
||||
the package. Note that many of the tests require root privileges and
|
||||
a specially crafted environment in order to run.
|
||||
|
||||
8. Type `make install' to install the programs and any data files and
|
||||
6. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
9. Type `make html' or `make pdf' to generate the html or pdf
|
||||
7. Type `make html' or `make pdf' to generate the html or pdf
|
||||
documentation. Note, these are not built by default.
|
||||
|
||||
10. You can remove the program binaries and object files from the
|
||||
8. 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
|
||||
|
||||
@ -36,6 +36,7 @@ library = {
|
||||
common = grub-core/kern/misc.c;
|
||||
common = grub-core/kern/partition.c;
|
||||
common = grub-core/lib/crypto.c;
|
||||
common = grub-core/lib/hwfeatures-gcry.c;
|
||||
common = grub-core/lib/json/json.c;
|
||||
common = grub-core/disk/luks.c;
|
||||
common = grub-core/disk/luks2.c;
|
||||
@ -43,6 +44,7 @@ library = {
|
||||
common = grub-core/disk/key_protector.c;
|
||||
common = grub-core/disk/cryptodisk.c;
|
||||
common = grub-core/disk/AFSplitter.c;
|
||||
common = grub-core/lib/argon2.c;
|
||||
common = grub-core/lib/pbkdf2.c;
|
||||
common = grub-core/commands/extcmd.c;
|
||||
common = grub-core/lib/arg.c;
|
||||
@ -162,6 +164,7 @@ library = {
|
||||
common = grub-core/io/gzio.c;
|
||||
common = grub-core/io/xzio.c;
|
||||
common = grub-core/io/lzopio.c;
|
||||
common = grub-core/io/zstdio.c;
|
||||
common = grub-core/kern/ia64/dl_helper.c;
|
||||
common = grub-core/kern/arm/dl_helper.c;
|
||||
common = grub-core/kern/arm64/dl_helper.c;
|
||||
@ -201,8 +204,8 @@ program = {
|
||||
extra_dist = util/grub-mkimagexx.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBLZMA)';
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
@ -225,8 +228,8 @@ program = {
|
||||
cflags = '-I$(srcdir)/grub-core/lib/tss2 -I$(srcdir)/grub-core/commands/tpm2_key_protector';
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBTASN1)';
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
@ -243,8 +246,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -258,8 +261,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -284,8 +287,8 @@ program = {
|
||||
|
||||
ldadd = '$(LIBLZMA)';
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -300,8 +303,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -323,8 +326,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -341,8 +344,8 @@ program = {
|
||||
cflags = '$(FUSE_CFLAGS)';
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM) $(FUSE_LIBS)';
|
||||
condition = COND_GRUB_MOUNT;
|
||||
@ -359,8 +362,8 @@ program = {
|
||||
cppflags = '-DGRUB_MKFONT=1';
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(FREETYPE_LIBS)';
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
@ -378,8 +381,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -436,8 +439,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -451,8 +454,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -466,8 +469,8 @@ program = {
|
||||
common = grub-core/kern/emu/argp_common.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -605,8 +608,8 @@ program = {
|
||||
|
||||
ldadd = '$(LIBLZMA)';
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
|
||||
@ -652,8 +655,8 @@ program = {
|
||||
|
||||
ldadd = '$(LIBLZMA)';
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -691,8 +694,8 @@ program = {
|
||||
|
||||
ldadd = '$(LIBLZMA)';
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -727,8 +730,8 @@ program = {
|
||||
|
||||
ldadd = '$(LIBLZMA)';
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -911,6 +914,12 @@ script = {
|
||||
common = tests/zfs_test.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase = native;
|
||||
name = zfs_zstd_test;
|
||||
common = tests/zfs_zstd_test.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase = native;
|
||||
name = cpio_test;
|
||||
@ -1285,13 +1294,13 @@ script = {
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase = native;
|
||||
testcase = nonnative;
|
||||
name = asn1_test;
|
||||
common = tests/asn1_test.in;
|
||||
};
|
||||
|
||||
script = {
|
||||
testcase = native;
|
||||
testcase = nonnative;
|
||||
name = tpm2_key_protector_test;
|
||||
common = tests/tpm2_key_protector_test.in;
|
||||
};
|
||||
@ -1305,8 +1314,8 @@ program = {
|
||||
common = grub-core/kern/misc.c;
|
||||
common = grub-core/tests/lib/test.c;
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1320,8 +1329,8 @@ program = {
|
||||
common = grub-core/kern/misc.c;
|
||||
common = grub-core/tests/lib/test.c;
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1335,8 +1344,8 @@ program = {
|
||||
common = grub-core/kern/misc.c;
|
||||
common = grub-core/tests/lib/test.c;
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1351,8 +1360,8 @@ program = {
|
||||
common = grub-core/tests/lib/test.c;
|
||||
common = grub-core/lib/priority_queue.c;
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
condition = COND_HAVE_CXX;
|
||||
@ -1367,8 +1376,8 @@ program = {
|
||||
common = grub-core/kern/misc.c;
|
||||
common = grub-core/tests/lib/test.c;
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1382,8 +1391,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1400,8 +1409,8 @@ program = {
|
||||
common = grub-core/kern/emu/argp_common.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1416,8 +1425,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1434,8 +1443,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
@ -1463,8 +1472,8 @@ program = {
|
||||
common = grub-core/osdep/init.c;
|
||||
|
||||
ldadd = libgrubmods.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = libgrubkern.a;
|
||||
ldadd = libgrubgcry.a;
|
||||
ldadd = grub-core/lib/gnulib/libgnu.a;
|
||||
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
|
||||
};
|
||||
|
||||
23
NEWS
23
NEWS
@ -1,3 +1,26 @@
|
||||
New in 2.14:
|
||||
|
||||
* libgcrypt 1.11.
|
||||
* LVM LV integrity and cachevol support.
|
||||
* EROFS support.
|
||||
* GRUB environment block inside the Btrfs header support.
|
||||
* NX support for EFI platforms.
|
||||
* shim loader protocol support.
|
||||
* BLS and UKI support.
|
||||
* Argon2 KDF support.
|
||||
* TPM2 key protector support.
|
||||
* Appended Signature Secure Boot Support for PowerPC.
|
||||
* New option to block command line interface.
|
||||
* Support dates outside of 1901..2038 range.
|
||||
* zstdio decompression support.
|
||||
* EFI code improvements and fixes.
|
||||
* TPM driver fixes.
|
||||
* Filesystems fixes.
|
||||
* CVE and Coverity fixes.
|
||||
* Tests improvements.
|
||||
* Documentation improvements.
|
||||
* ... and tons of other fixes and cleanups...
|
||||
|
||||
New in 2.12:
|
||||
|
||||
* GCC 13 support.
|
||||
|
||||
@ -79,6 +79,11 @@ AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE],
|
||||
[AC_MSG_CHECKING([whether ${TARGET_OBJCOPY} works for absolute addresses])
|
||||
AC_CACHE_VAL(grub_cv_prog_objcopy_absolute,
|
||||
[cat > conftest.c <<\EOF
|
||||
asm (
|
||||
".globl start, _start, __start\n"
|
||||
".ifdef cmain; .set start = _start = __start = cmain\n.endif\n"
|
||||
".ifdef _cmain; .set start = _start = __start = _cmain\n.endif\n"
|
||||
);
|
||||
void cmain (void);
|
||||
void
|
||||
cmain (void)
|
||||
|
||||
11
autogen.sh
11
autogen.sh
@ -52,6 +52,17 @@ for x in mpi-asm-defs.h mpih-add1.c mpih-sub1.c mpih-mul1.c mpih-mul2.c mpih-mul
|
||||
cp grub-core/lib/libgcrypt-grub/mpi/generic/"$x" grub-core/lib/libgcrypt-grub/mpi/"$x"
|
||||
done
|
||||
|
||||
for x in sha256-ssse3-amd64.S sha256-avx-amd64.S sha256-avx2-bmi2-amd64.S sha256-intel-shaext.c sha512-ssse3-amd64.S sha512-avx-amd64.S sha512-avx2-bmi2-amd64.S sha512-avx512-amd64.S; do
|
||||
if [ -h grub-core/lib/libgcrypt-grub/cipher/"$x" ] || [ -f grub-core/lib/libgcrypt-grub/cipher/"$x" ]; then
|
||||
rm grub-core/lib/libgcrypt-grub/cipher/"$x"
|
||||
fi
|
||||
cp grub-core/lib/libgcrypt/cipher/"$x" grub-core/lib/libgcrypt-grub/cipher/"$x"
|
||||
done
|
||||
|
||||
if [ -f grub-core/lib/libgcrypt-grub/src/hwfeatures.c ]; then
|
||||
rm grub-core/lib/libgcrypt-grub/src/hwfeatures.c
|
||||
fi
|
||||
|
||||
for x in grub-core/lib/libgcrypt-patches/*.patch; do
|
||||
patch -i $x -p1
|
||||
done
|
||||
|
||||
@ -24,6 +24,7 @@ gnulib_modules="
|
||||
argp
|
||||
base64
|
||||
error
|
||||
filevercmp
|
||||
fnmatch
|
||||
getdelim
|
||||
getline
|
||||
@ -62,8 +63,6 @@ checkout_only_file=
|
||||
copy=true
|
||||
vc_ignore=
|
||||
|
||||
SKIP_PO=t
|
||||
|
||||
# Build prerequisites
|
||||
buildreq="\
|
||||
autoconf 2.64
|
||||
@ -107,4 +106,23 @@ bootstrap_post_import_hook () {
|
||||
|
||||
bootstrap_epilogue () {
|
||||
mv INSTALL.grub INSTALL
|
||||
|
||||
if [ "x$SKIP_PO" = "x" ]; then
|
||||
# Generate LINGUAS with all supported languages. Bootstrap will
|
||||
# generate a LINGUAS, but it will not contain the autogenerated
|
||||
# languages.
|
||||
autogenerated="en@quot en@hebrew de@hebrew en@cyrillic en@greek en@arabic en@piglatin de_CH"
|
||||
|
||||
{
|
||||
# NOTE: xargs has no POSIX compliant way to avoid running the program
|
||||
# given as an argument when there are no input lines. So ensure that
|
||||
# basename is always run with at least one argument, the empty string,
|
||||
# and ignore the first line of output.
|
||||
ls po/*.po | xargs -L 100 basename -s .po -a "" | tail -n +2
|
||||
for x in $autogenerated; do
|
||||
rm -f "po/$x.po"
|
||||
echo "$x"
|
||||
done
|
||||
} | sort | uniq | xargs >po/LINGUAS
|
||||
fi
|
||||
}
|
||||
|
||||
@ -24,6 +24,8 @@ if COND_HAVE_PCI
|
||||
CFLAGS_PLATFORM += -DGRUB_HAS_PCI
|
||||
endif
|
||||
|
||||
CPPFLAGS_GCRY_ASM = @CPPFLAGS_GCRY_ASM@
|
||||
|
||||
# Other options
|
||||
|
||||
CPPFLAGS_DEFAULT = -DGRUB_FILE=\"$(subst $(srcdir)/,,$<)\"
|
||||
|
||||
@ -34,23 +34,63 @@ EXTRA_DIST += grub-core/lib/gnulib-patches/fix-regexec-resource-leak.patch
|
||||
EXTRA_DIST += grub-core/lib/gnulib-patches/fix-gcc-15-compile.patch
|
||||
EXTRA_DIST += grub-core/lib/gnulib-patches/fix-unused-value.patch
|
||||
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/01_md.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/02_keccak_sse.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/03_mpiutil_alloc.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/03_sexp_free.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/04_aria.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/05_disable_rsa_shake.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/06_blake.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/07_disable_64div.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/08_sexp_leak.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/09-blake2b-hash-buffers.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/10-kdf-use-GPG-errs.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/11-kdf-remove-unsupported-kdfs.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/12-kdf-use-grub_divmod64.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/13_add_hwfeatures.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/14_fix_build_shaext.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/15_build_sha256_x86_64_efi_opt_code.patch
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-patches/16_build_sha512_x86_64_efi_opt_code.patch
|
||||
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0007-asn1_test-include-asn1_test.h-only.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0008-asn1_test-rename-the-main-functions-to-the-test-name.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0009-asn1_test-return-either-0-or-1-to-reflect-the-result.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0010-asn1_test-remove-verbose-and-the-unnecessary-printf.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0011-asn1_test-print-the-error-messages-with-grub_printf.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0012-asn1_test-use-the-grub-specific-functions-and-types.patch
|
||||
EXTRA_DIST += grub-core/lib/libtasn1-patches/0013-asn1_test-enable-the-testcase-only-when-GRUB_LONG_MA.patch
|
||||
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt
|
||||
EXTRA_DIST += grub-core/lib/libgcrypt-grub/mpi/generic
|
||||
EXTRA_DIST += grub-core/lib/libtasn1
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/include -name '*.h')
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/lib -name '*.h')
|
||||
EXTRA_DIST += grub-core/efiemu/runtime/config.h
|
||||
EXTRA_DIST += grub-core/tests/crypto_cipher_mode_vectors.h
|
||||
EXTRA_DIST += grub-core/tests/asn1/asn1_test.h
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/tests/asn1/tests -name '*.h')
|
||||
EXTRA_DIST += $(shell find $(top_srcdir)/grub-core/commands/tpm2_key_protector -name '*.h')
|
||||
EXTRA_DIST += grub-core/commands/tpm2_key_protector/tpm2key.asn
|
||||
|
||||
EXTRA_DIST += grub-core/commands/appendedsig/appendedsig.h
|
||||
|
||||
EXTRA_DIST += grub-core/lib/LzmaDec.c
|
||||
|
||||
EXTRA_DIST += grub-core/fs/cpio_common.c
|
||||
|
||||
EXTRA_DIST += BUGS
|
||||
EXTRA_DIST += MAINTAINERS
|
||||
EXTRA_DIST += SECURITY
|
||||
EXTRA_DIST += util/i386/efi/grub-dumpdevtree
|
||||
EXTRA_DIST += util/spkmodem-recv.c
|
||||
EXTRA_DIST += util/import_gcrypth.sed
|
||||
EXTRA_DIST += util/import_gcrypt_inth.sed
|
||||
EXTRA_DIST += util/bin2h.c
|
||||
EXTRA_DIST += util/grub-gen-asciih.c
|
||||
EXTRA_DIST += util/grub-gen-widthspec.c
|
||||
@ -132,6 +172,9 @@ EXTRA_DIST += po/hebrew.sed
|
||||
|
||||
EXTRA_DIST += tests/dfly-mbr-mbexample.mbr.img.gz
|
||||
EXTRA_DIST += tests/dfly-mbr-mbexample.dfly.img.gz
|
||||
EXTRA_DIST += tests/iso9660_ce_loop2.iso.gz
|
||||
EXTRA_DIST += tests/iso9660_ce_loop.iso.gz
|
||||
EXTRA_DIST += tests/iso9660_early_ce.iso.gz
|
||||
|
||||
EXTRA_DIST += coreboot.cfg
|
||||
|
||||
@ -142,6 +185,8 @@ EXTRA_DIST += tests/file_filter/file.lzop
|
||||
EXTRA_DIST += tests/file_filter/file.lzop.sig
|
||||
EXTRA_DIST += tests/file_filter/file.xz
|
||||
EXTRA_DIST += tests/file_filter/file.xz.sig
|
||||
EXTRA_DIST += tests/file_filter/file.zstd
|
||||
EXTRA_DIST += tests/file_filter/file.zstd.sig
|
||||
EXTRA_DIST += tests/file_filter/keys
|
||||
EXTRA_DIST += tests/file_filter/keys.pub
|
||||
EXTRA_DIST += tests/file_filter/test.cfg
|
||||
|
||||
286
configure.ac
286
configure.ac
@ -34,7 +34,7 @@ dnl "TARGET_" (such as TARGET_CC, TARGET_CFLAGS, etc.) are used for
|
||||
dnl the target type. See INSTALL for full list of variables and
|
||||
dnl description of the relationships between them.
|
||||
|
||||
AC_INIT([GRUB],[2.13],[bug-grub@gnu.org])
|
||||
AC_INIT([GRUB],[2.15],[bug-grub@gnu.org])
|
||||
|
||||
AS_CASE(["$ERROR_PLATFORM_NOT_SUPPORT_SSP"],
|
||||
[n | no | nO | N | No | NO], [ERROR_PLATFORM_NOT_SUPPORT_SSP=no],
|
||||
@ -53,7 +53,7 @@ save_program_prefix="${program_prefix}"
|
||||
AC_CANONICAL_TARGET
|
||||
program_prefix="${save_program_prefix}"
|
||||
|
||||
AM_INIT_AUTOMAKE([1.11])
|
||||
AM_INIT_AUTOMAKE([1.11 tar-ustar])
|
||||
AC_PREREQ(2.64)
|
||||
AC_CONFIG_SRCDIR([include/grub/dl.h])
|
||||
AC_CONFIG_HEADERS([config-util.h])
|
||||
@ -1148,6 +1148,239 @@ if test "x$grub_cv_cc_fno_ident" = xyes; then
|
||||
TARGET_CFLAGS="$TARGET_CFLAGS -fno-ident"
|
||||
fi
|
||||
|
||||
# Implementation of the --disable-amd64-as-feature-detection switch.
|
||||
AC_MSG_CHECKING([whether to enable AMD64 as(1) feature detection])
|
||||
if test x$target_cpu = xx86_64 -a x$platform = xefi; then
|
||||
CPPFLAGS_GCRY_ASM="-D__x86_64 -DHAVE_CPU_ARCH_X86"
|
||||
AC_ARG_ENABLE(amd64-as-feature-detection,
|
||||
AS_HELP_STRING([--disable-amd64-as-feature-detection],
|
||||
[Disable the auto-detection of AMD64 as(1) features]),
|
||||
[amd64_as_feature_detection=$enableval],
|
||||
[amd64_as_feature_detection=yes])
|
||||
else
|
||||
CPPFLAGS_GCRY_ASM=
|
||||
amd64_as_feature_detection=no
|
||||
fi
|
||||
AC_MSG_RESULT($amd64_as_feature_detection)
|
||||
|
||||
#
|
||||
# Check whether GCC assembler supports features needed for libgcrypt amd64
|
||||
# implementations
|
||||
#
|
||||
if test $amd64_as_feature_detection = yes; then
|
||||
AC_CACHE_CHECK([whether GCC assembler is compatible for amd64 assembly implementations],
|
||||
[grub_cv_gcc_x86_platform_as_ok],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_x86_platform_as_ok="n/a"
|
||||
else
|
||||
grub_cv_gcc_x86_platform_as_ok=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[__asm__(
|
||||
/* Test if '.type' and '.size' are supported. */
|
||||
/* These work only on ELF targets. */
|
||||
".text\n\t"
|
||||
"asmfunc:\n\t"
|
||||
".size asmfunc,.-asmfunc;\n\t"
|
||||
".type asmfunc,@function;\n\t"
|
||||
/* Test if assembler allows use of '/' for constant division
|
||||
* (Solaris/x86 issue). If previous constant division check
|
||||
* and "-Wa,--divide" workaround failed, this causes assembly
|
||||
* to be disable on this machine. */
|
||||
"xorl \$(123456789/12345678), %ebp;\n\t"
|
||||
);
|
||||
void asmfunc(void);]], [ asmfunc(); ])],
|
||||
[grub_cv_gcc_x86_platform_as_ok=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_x86_platform_as_ok" = "yes"; then
|
||||
# Define __PIC__ to ensure the assembly code use PIC instructions
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -D__PIC__=1 -DHAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC assembler supports Intel syntax
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC assembler is compatible for Intel syntax assembly implementations],
|
||||
[grub_cv_gcc_platform_as_ok_for_intel_syntax],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_platform_as_ok_for_intel_syntax="n/a"
|
||||
else
|
||||
grub_cv_gcc_platform_as_ok_for_intel_syntax=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[__asm__(
|
||||
".intel_syntax noprefix\n\t"
|
||||
".text\n\t"
|
||||
"actest:\n\t"
|
||||
"pxor xmm1, xmm7;\n\t"
|
||||
"vperm2i128 ymm2, ymm3, ymm0, 1;\n\t"
|
||||
"add eax, ebp;\n\t"
|
||||
"rorx eax, ebp, 1;\n\t"
|
||||
"sub eax, [esp + 4];\n\t"
|
||||
"add dword ptr [esp + eax], 0b10101;\n\t"
|
||||
".att_syntax prefix\n\t"
|
||||
);
|
||||
void actest(void);]], [ actest(); ])],
|
||||
[grub_cv_gcc_platform_as_ok_for_intel_syntax=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_platform_as_ok_for_intel_syntax" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_INTEL_SYNTAX_PLATFORM_AS"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC inline assembler supports SSSE3 instructions
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC inline assembler supports SSSE3 instructions],
|
||||
[grub_cv_gcc_inline_asm_ssse3],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_inline_asm_ssse3="n/a"
|
||||
else
|
||||
grub_cv_gcc_inline_asm_ssse3=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[static unsigned char be_mask[16] __attribute__ ((aligned (16))) =
|
||||
{ 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
void a(void) {
|
||||
__asm__("pshufb %[mask], %%xmm2\n\t"::[mask]"m"(*be_mask):);
|
||||
}]], [ a(); ] )],
|
||||
[grub_cv_gcc_inline_asm_ssse3=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_inline_asm_ssse3" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_SSSE3"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC inline assembler supports SHA Extensions instructions.
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC inline assembler supports SHA Extensions instructions],
|
||||
[grub_cv_gcc_inline_asm_shaext],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_inline_asm_shaext="n/a"
|
||||
else
|
||||
grub_cv_gcc_inline_asm_shaext=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[void a(void) {
|
||||
__asm__("sha1rnds4 \$0, %%xmm1, %%xmm3\n\t":::"cc");
|
||||
__asm__("sha1nexte %%xmm1, %%xmm3\n\t":::"cc");
|
||||
__asm__("sha1msg1 %%xmm1, %%xmm3\n\t":::"cc");
|
||||
__asm__("sha1msg2 %%xmm1, %%xmm3\n\t":::"cc");
|
||||
__asm__("sha256rnds2 %%xmm0, %%xmm1, %%xmm3\n\t":::"cc");
|
||||
__asm__("sha256msg1 %%xmm1, %%xmm3\n\t":::"cc");
|
||||
__asm__("sha256msg2 %%xmm1, %%xmm3\n\t":::"cc");
|
||||
}]], [ a(); ] )],
|
||||
[grub_cv_gcc_inline_asm_shaext=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_inline_asm_shaext" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_SHAEXT -DENABLE_SHAEXT_SUPPORT"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC inline assembler supports SSE4.1 instructions.
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC inline assembler supports SSE4.1 instructions],
|
||||
[grub_cv_gcc_inline_asm_sse41],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_inline_asm_sse41="n/a"
|
||||
else
|
||||
grub_cv_gcc_inline_asm_sse41=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[void a(void) {
|
||||
int i;
|
||||
__asm__("pextrd \$2, %%xmm0, %[out]\n\t" : [out] "=m" (i));
|
||||
}]], [ a(); ] )],
|
||||
[grub_cv_gcc_inline_asm_sse41=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_inline_asm_sse41" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_SSE41"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC inline assembler supports AVX instructions
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC inline assembler supports AVX instructions],
|
||||
[grub_cv_gcc_inline_asm_avx],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_inline_asm_avx="n/a"
|
||||
else
|
||||
grub_cv_gcc_inline_asm_avx=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[void a(void) {
|
||||
__asm__("xgetbv; vaesdeclast (%[mem]),%%xmm0,%%xmm7\n\t"::[mem]"r"(0):);
|
||||
}]], [ a(); ] )],
|
||||
[grub_cv_gcc_inline_asm_avx=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_inline_asm_avx" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_AVX"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC inline assembler supports AVX2 instructions
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC inline assembler supports AVX2 instructions],
|
||||
[grub_cv_gcc_inline_asm_avx2],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_inline_asm_avx2="n/a"
|
||||
else
|
||||
grub_cv_gcc_inline_asm_avx2=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[void a(void) {
|
||||
__asm__("xgetbv; vpbroadcastb %%xmm7,%%ymm1\n\t":::"cc");
|
||||
}]], [ a(); ] )],
|
||||
[grub_cv_gcc_inline_asm_avx2=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_inline_asm_avx2" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_AVX2"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC inline assembler supports AVX512 instructions
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC inline assembler supports AVX512 instructions],
|
||||
[grub_cv_gcc_inline_asm_avx512],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_inline_asm_avx512="n/a"
|
||||
else
|
||||
grub_cv_gcc_inline_asm_avx512=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[void a(void) {
|
||||
__asm__("xgetbv; vpopcntq %%zmm7, %%zmm1%{%%k1%}%{z%};\n\t":::"cc");
|
||||
__asm__("vpexpandb %%zmm3, %%zmm1;\n\t":::"cc");
|
||||
__asm__("vpxorq %%xmm7, %%xmm7, %%xmm7;\n\t":::"cc");
|
||||
__asm__("vpxorq %%ymm7, %%ymm7, %%ymm7;\n\t":::"cc");
|
||||
__asm__("vpxorq (%%eax)%{1to8%}, %%zmm7, %%zmm7;\n\t":::"cc");
|
||||
}]], [ a(); ] )],
|
||||
[grub_cv_gcc_inline_asm_avx512=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_inline_asm_avx512" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_AVX512"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check whether GCC inline assembler supports BMI2 instructions
|
||||
#
|
||||
AC_CACHE_CHECK([whether GCC inline assembler supports BMI2 instructions],
|
||||
[grub_cv_gcc_inline_asm_bmi2],
|
||||
[if test "$target_cpu" != "x86_64" ; then
|
||||
grub_cv_gcc_inline_asm_bmi2="n/a"
|
||||
else
|
||||
grub_cv_gcc_inline_asm_bmi2=no
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[[unsigned int a(unsigned int x, unsigned int y) {
|
||||
unsigned int tmp1, tmp2;
|
||||
asm ("rorxl %2, %1, %0"
|
||||
: "=r" (tmp1)
|
||||
: "rm0" (x), "J" (32 - ((23) & 31)));
|
||||
asm ("andnl %2, %1, %0"
|
||||
: "=r" (tmp2)
|
||||
: "r0" (x), "rm" (y));
|
||||
return tmp1 + tmp2;
|
||||
}]], [ a(1, 2); ] )],
|
||||
[grub_cv_gcc_inline_asm_bmi2=yes])
|
||||
fi])
|
||||
if test "$grub_cv_gcc_inline_asm_bmi2" = "yes" ; then
|
||||
CPPFLAGS_GCRY_ASM="$CPPFLAGS_GCRY_ASM -DHAVE_GCC_INLINE_ASM_BMI2"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(CPPFLAGS_GCRY_ASM)
|
||||
|
||||
CFLAGS="$TARGET_CFLAGS"
|
||||
|
||||
|
||||
@ -1228,7 +1461,6 @@ elif test x$grub_cv_target_cc_link_format = x-mi386pe || test x$grub_cv_target_c
|
||||
TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/i386-cygwin-img-ld.sc"
|
||||
TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}"
|
||||
TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/i386-cygwin-img-ld.sc"
|
||||
TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
|
||||
TARGET_IMG_CFLAGS=
|
||||
else
|
||||
TARGET_APPLE_LINKER=0
|
||||
@ -1236,7 +1468,6 @@ else
|
||||
TARGET_IMG_LDSCRIPT=
|
||||
TARGET_IMG_LDFLAGS='-Wl,-N'
|
||||
TARGET_IMG_LDFLAGS_AC='-Wl,-N'
|
||||
TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
|
||||
TARGET_IMG_CFLAGS=
|
||||
fi
|
||||
|
||||
@ -1312,21 +1543,6 @@ AC_SUBST(TARGET_LDFLAGS_OLDMAGIC)
|
||||
|
||||
LDFLAGS="$TARGET_LDFLAGS"
|
||||
|
||||
if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then
|
||||
# Use large model to support 4G memory
|
||||
AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [
|
||||
CFLAGS="$TARGET_CFLAGS -mcmodel=large"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
|
||||
[grub_cv_cc_mcmodel=yes],
|
||||
[grub_cv_cc_mcmodel=no])
|
||||
])
|
||||
if test "x$grub_cv_cc_mcmodel" = xyes; then
|
||||
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large"
|
||||
elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then
|
||||
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany"
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$target_cpu"-"$platform" = x86_64-efi; then
|
||||
# EFI writes to stack below %rsp, we must not use the red zone
|
||||
AC_CACHE_CHECK([whether option -mno-red-zone works], grub_cv_cc_no_red_zone, [
|
||||
@ -1435,6 +1651,21 @@ fi]
|
||||
|
||||
CFLAGS="$TARGET_CFLAGS"
|
||||
|
||||
if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then
|
||||
# Use large model to support 4G memory
|
||||
AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [
|
||||
CFLAGS="$TARGET_CFLAGS -mcmodel=large"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])],
|
||||
[grub_cv_cc_mcmodel=yes],
|
||||
[grub_cv_cc_mcmodel=no])
|
||||
])
|
||||
if test "x$grub_cv_cc_mcmodel" = xyes; then
|
||||
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large"
|
||||
elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then
|
||||
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Stack smashing protector.
|
||||
grub_CHECK_STACK_PROTECTOR
|
||||
AC_ARG_ENABLE([stack-protector],
|
||||
@ -1561,7 +1792,24 @@ LIBS=""
|
||||
# Defined in acinclude.m4.
|
||||
grub_ASM_USCORE
|
||||
grub_PROG_TARGET_CC
|
||||
|
||||
# The error message produced by autoconf if autoconf-archive is not installed is
|
||||
# quite misleading and not very helpful. So, try point people in the right direction.
|
||||
m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
|
||||
|
||||
if test "x$TARGET_APPLE_LINKER" != x1 ; then
|
||||
AX_CHECK_LINK_FLAG([-Wl,--image-base,0x400000],
|
||||
[TARGET_IMG_BASE_LDOPT="-Wl,--image-base"],
|
||||
[TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"],
|
||||
[],
|
||||
[AC_LANG_SOURCE([
|
||||
asm (".globl start; start:");
|
||||
asm (".globl _start; _start:");
|
||||
asm (".globl __start; __start:");
|
||||
void __main (void);
|
||||
void __main (void) {}
|
||||
int main (void);
|
||||
])])
|
||||
grub_PROG_OBJCOPY_ABSOLUTE
|
||||
fi
|
||||
grub_PROG_LD_BUILD_ID_NONE
|
||||
|
||||
@ -77,7 +77,7 @@ This edition documents version @value{VERSION}.
|
||||
* Coding style::
|
||||
* Finding your way around::
|
||||
* Contributing Changes::
|
||||
* Setting up and running test suite::
|
||||
* Tests::
|
||||
* Updating External Code::
|
||||
* Debugging::
|
||||
* Porting::
|
||||
@ -485,8 +485,17 @@ If your intention is to just get started, please do not submit a inclusion
|
||||
request. Instead, please subscribe to the mailing list, and communicate first
|
||||
(e.g. sending a patch, asking a question, commenting on another message...).
|
||||
|
||||
@node Tests
|
||||
@chapter Tests
|
||||
|
||||
@menu
|
||||
* Setting up and running test suite::
|
||||
* Writing new tests::
|
||||
@end menu
|
||||
|
||||
|
||||
@node Setting up and running test suite
|
||||
@chapter Setting up and running test suite
|
||||
@section Setting up and running test suite
|
||||
|
||||
GRUB is basically a tiny operating system with read support for many file
|
||||
systems and which has been ported to a variety of architectures. As such, its
|
||||
@ -495,6 +504,47 @@ These dependencies are currently documented in the
|
||||
@uref{https://git.savannah.gnu.org/cgit/grub.git/tree/INSTALL, INSTALL}
|
||||
file in the source repository. Once installed, the test suite can be started
|
||||
by running the @command{make check} command from the GRUB build directory.
|
||||
To properly run all the tests, the test suite must be run as the privileged
|
||||
user, for instance to run the filesystem tests, which require mounting
|
||||
filesystem images. Of course, virtualization or containers may be used, but
|
||||
this requires extra configuration outside the scope of this document.
|
||||
|
||||
@node Writing new tests
|
||||
@section Writing new tests
|
||||
|
||||
There are two kinds of tests in the GRUB test suite: native and non-native.
|
||||
Native tests are those which run on the build architecture and non-native
|
||||
run on the target architecture. The non-native tests are run in a QEMU
|
||||
virtual machine using the grub-shell script in tests/util. When writing a
|
||||
new test, first determine if it should run on the host or the target and
|
||||
then look at the existing tests as examples of how to they should be written.
|
||||
|
||||
The GRUB test suite uses automake (@uref{https://www.gnu.org/software/automake/manual/automake.html#Tests, see documention here}). One thing of importance
|
||||
to note is that tests have 4 classes of return codes: SKIP (77), HARD ERROR
|
||||
(99), PASS (0), and FAIL (all other codes). A
|
||||
@uref{https://www.gnu.org/software/automake/manual/automake.html#index-test-skip, SKIP return code}
|
||||
should be returned when this test cannot be performed and thus should be
|
||||
skipped. Typically this is because the target does not support the test,
|
||||
such as the ohci USB test for the powerpc-ieee1275 target because there
|
||||
are no native drivers for that target. A
|
||||
@uref{https://www.gnu.org/software/automake/manual/automake.html#index-Distinction-between-errors-and-failures-in-testsuites, HARD ERROR return code}
|
||||
should be returned when a failure in something other than what is intended
|
||||
to be tested happens. This is commonly returned when the test cannot be
|
||||
properly run because of deficiencies in the test environment, eg. when
|
||||
testing the xfs filesystem, but the kernel has no support for mounting xfs
|
||||
volumes. A SKIP should never be returned for a HARD ERROR condition
|
||||
because at best the person running the test does not know if the test was
|
||||
skipped because it doesn't apply to the target or because the tester failed
|
||||
to setup the environment properly. At worst, the tester will believe that
|
||||
everything is okay without realizing that the tests are not covering all
|
||||
the code that it should.
|
||||
|
||||
Keep portability in mind while creating a new tests so that the tests can be
|
||||
run on a variety of systems and shells. Do not use bashisms. Also try to avoid
|
||||
using utilities that would unecessarily add software dependencies. Sometimes
|
||||
this is unavoidable. Copy or adapt existing test implementations where feasible.
|
||||
If the test is native and requires root, make sure to check that the test is
|
||||
run with the root user and return HARD ERROR if it is not.
|
||||
|
||||
@node Updating External Code
|
||||
@chapter Updating external code
|
||||
@ -900,26 +950,26 @@ is to be run in a GDB session running with the @file{gdb_grub} GDB script.
|
||||
@node Porting
|
||||
@chapter Porting
|
||||
|
||||
GRUB2 is designed to be easily portable accross platforms. But because of the
|
||||
GRUB2 is designed to be easily portable across platforms. But because of the
|
||||
nature of bootloader every new port must be done separately. Here is how I did
|
||||
MIPS (loongson and ARC) and Xen ports. Note than this is more of suggestions,
|
||||
not absolute truth.
|
||||
MIPS (loongson and ARC) and Xen ports. Note that this is more of a suggestion,
|
||||
and not absolute truth.
|
||||
|
||||
First of all grab any architecture specifications you can find in public
|
||||
(please avoid NDA).
|
||||
First of all, grab any architecture specifications you can find in the public
|
||||
domain (please avoid NDA).
|
||||
|
||||
First stage is ``Hello world''. I've done it outside of GRUB for simplicity.
|
||||
Your task is to have a small program which is loadable as bootloader and
|
||||
clearly shows its presence to you. If you have easily accessible console
|
||||
you can just print a message. If you have a mapped framebuffer you know address
|
||||
clearly shows its presence to you. If you have an easily accessible console
|
||||
you can just print a message. If you have a mapped framebuffer you know the address
|
||||
of, you can draw a square. If you have a debug facility, just hanging without
|
||||
crashing might be enough. For the first stage you can choose to load the
|
||||
bootloader across the network since format for network image is often easier
|
||||
crashing might be enough. For the first stage, you can choose to load the
|
||||
bootloader across the network since the format for a network image is often easier
|
||||
than for local boot and it skips the need of small intermediary stages and
|
||||
nvram handling. Additionally you can often have a good idea of the needed
|
||||
format by running ``file'' on any netbootable executable for given platform.
|
||||
nvram handling. Additionally, you can often have a good idea of the needed
|
||||
format by running ``file'' on any netbootable executable for the given platform.
|
||||
|
||||
This program should probably have 2 parts: an assembler and C one. Assembler one
|
||||
This program should probably have 2 parts: an assembler and C one. The assembler one
|
||||
handles BSS cleaning and other needed setup (on some platforms you may need
|
||||
to switch modes or copy the executable to its definitive position). So your code
|
||||
may look like (x86 assembly for illustration purposes)
|
||||
@ -961,12 +1011,12 @@ Sometimes you need a third file: assembly stubs for ABI-compatibility.
|
||||
|
||||
Once this file is functional it's time to move it into GRUB2. The startup
|
||||
assembly file goes to grub-core/kern/$cpu/$platform/startup.S. You should also
|
||||
include grub/symbol.h and replace call to entry point with call to
|
||||
include grub/symbol.h and replace the call to entry point with call to
|
||||
EXT_C(grub_main). The C file goes to grub-core/kern/$cpu/$platform/init.c
|
||||
and its entry point is renamed to void grub_machine_init (void). Keep final
|
||||
infinite loop for now. Stubs file if any goes to
|
||||
infinite loop for now. Stub files if any goes to
|
||||
grub-core/kern/$cpu/$platform/callwrap.S. Sometimes either $cpu or $platform
|
||||
is dropped if file is used on several cpus respectivelyplatforms.
|
||||
is dropped if file is used on several cpus respectively or platforms.
|
||||
Check those locations if they already have what you're looking for.
|
||||
|
||||
Then modify in configure.ac the following parts:
|
||||
@ -984,10 +1034,10 @@ esac
|
||||
@end example
|
||||
|
||||
Sometimes CPU have additional architecture names which don't influence booting.
|
||||
You might want to have some canonical name to avoid having bunch of identical
|
||||
You might want to have some canonical name to avoid having a bunch of identical
|
||||
platforms with different names.
|
||||
|
||||
NOTE: it doesn't influence compile optimisations which depend solely on
|
||||
NOTE: It doesn't influence compile optimisations which depend solely on
|
||||
chosen compiler and compile options.
|
||||
|
||||
@example
|
||||
@ -1049,7 +1099,7 @@ AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platf
|
||||
@end example
|
||||
|
||||
Next stop is gentpl.py. You need to add your platform to the list of supported
|
||||
ones (sorry that this list is duplicated):
|
||||
ones (unfortunately, this list is duplicated):
|
||||
|
||||
@example
|
||||
GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
|
||||
@ -1059,21 +1109,21 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
|
||||
"mips_qemu_mips", "s390_mainframe" ]
|
||||
@end example
|
||||
|
||||
You may also want already to add new platform to one or several of available
|
||||
Now you may also want to add a new platform to one or several of available
|
||||
groups. In particular we always have a group for each CPU even when only
|
||||
one platform for given CPU is available.
|
||||
|
||||
Then comes grub-core/Makefile.core.def. In the block ``kernel'' you'll need
|
||||
to define ldflags for your platform ($cpu_$platform_ldflags). You also need to
|
||||
declare startup asm file ($cpu_$platform_startup) as well as any other files
|
||||
(e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
|
||||
At this stage you will also need to add dummy dl.c and cache.S with functions
|
||||
declare a startup asm file ($cpu_$platform_startup) as well as any other files,
|
||||
like init.c or callwrap.S (e.g. $cpu_$platform = kern/$cpu/$platform/init.c).
|
||||
At this stage, you will also need to add a dummy dl.c and cache.S with functions
|
||||
grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t
|
||||
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and
|
||||
void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They
|
||||
won't be used for now.
|
||||
|
||||
You will need to create directory include/$cpu/$platform and a file
|
||||
You will need to create a directory include/$cpu/$platform and a file
|
||||
include/$cpu/types.h. The latter following this template:
|
||||
|
||||
@example
|
||||
@ -1097,7 +1147,7 @@ include/$cpu/types.h. The latter following this template:
|
||||
You will also need to add a dummy file to datetime and setjmp modules to
|
||||
avoid any of it having no files. It can be just completely empty at this stage.
|
||||
|
||||
You'll need to make grub-mkimage.c (util/grub_mkimage.c) aware of the needed
|
||||
You'll need to make grub-mkimage (in util/grub_mkimage.c) aware of the needed
|
||||
format. For most commonly used formats like ELF, PE, aout or raw the support
|
||||
is already present and you'll need to make it follow the existant code paths
|
||||
for your platform adding adjustments if necessary. When done compile:
|
||||
@ -1108,47 +1158,47 @@ for your platform adding adjustments if necessary. When done compile:
|
||||
make > /dev/null
|
||||
@end example
|
||||
|
||||
And create image
|
||||
And create an image:
|
||||
|
||||
@example
|
||||
./grub-mkimage -d grub-core -O $format_id -o test.img
|
||||
@end example
|
||||
|
||||
And it's time to test your test.img.
|
||||
And now it's time to test your test.img.
|
||||
|
||||
If it works next stage is to have heap, console and timer.
|
||||
If it works, the next stage is to have a heap, console and timer.
|
||||
|
||||
To have the heap working you need to determine which regions are suitable for
|
||||
heap usage, allocate them from firmware and map (if applicable). Then call
|
||||
grub_mm_init_region (void *start, grub_size_t s) for every of this region.
|
||||
As a shortcut for early port you can allocate right after _end or have
|
||||
a big static array for heap. If you do you'll probably need to come back to
|
||||
heap usage, allocate them from the firmware and map them, if applicable.
|
||||
Then call grub_mm_init_region (void *start, grub_size_t s) for each region.
|
||||
As a shortcut for an early port, you can allocate right after _end or have
|
||||
a big static array for heap. If you do, you'll probably need to come back to
|
||||
this later. As for output console you should distinguish between an array of
|
||||
text, terminfo or graphics-based console. Many of real-world examples don't
|
||||
text, terminfo or graphics-based console. Many real-world examples don't
|
||||
fit perfectly into any of these categories but one of the models is easier
|
||||
to be used as base. In second and third case you should add your platform to
|
||||
to be used as base. In the second and third case, you should add your platform to
|
||||
terminfokernel respectively videoinkernel group. A good example of array of
|
||||
text is i386-pc (kern/i386/pc/init.c and term/i386/pc/console.c).
|
||||
Of terminfo is ieee1275 (kern/ieee1275/init.c and term/ieee1275/console.c).
|
||||
Of video is loongson (kern/mips/loongson/init.c). Note that terminfo has
|
||||
text is i386-pc (kern/i386/pc/init.c and term/i386/pc/console.c),
|
||||
of terminfo is ieee1275 (kern/ieee1275/init.c and term/ieee1275/console.c),
|
||||
and of video is loongson (kern/mips/loongson/init.c). Note that terminfo has
|
||||
to be inited in 2 stages: one before (to get at least rudimentary console
|
||||
as early as possible) and another after the heap (to get full-featured console).
|
||||
For the input there are string of keys, terminfo and direct hardware. For string
|
||||
of keys look at i386-pc (same files), for terminfo ieee1275 (same files) and for
|
||||
hardware loongson (kern/mips/loongson/init.c and term/at_keyboard.c).
|
||||
For the input, there is a string of keys (eg. i386-pc, same files), terminfo
|
||||
(ieee1275, same files), and hardware (loongson, see kern/mips/loongson/init.c
|
||||
and term/at_keyboard.c).
|
||||
|
||||
For the timer you'll need to call grub_install_get_time_ms (...) with as sole
|
||||
argument a function returning a grub_uint64_t of a number of milliseconds
|
||||
For the timer, you'll need to call grub_install_get_time_ms (...) with the
|
||||
sole argument a function returning a grub_uint64_t number of milliseconds
|
||||
elapsed since arbitrary point in the past.
|
||||
|
||||
Once these steps accomplished you can remove the inifinite loop and you should
|
||||
Once these steps are accomplished, you can remove the inifinite loop and you should
|
||||
be able to get to the minimal console. Next step is to have module loading
|
||||
working. For this you'll need to fill kern/$cpu/dl.c and kern/$cpu/cache.S
|
||||
working. For this, you'll need to fill kern/$cpu/dl.c and kern/$cpu/cache.S
|
||||
with real handling of relocations and respectively the real sync of I and D
|
||||
caches. Also you'll need to decide where in the image to store the modules.
|
||||
Usual way is to have it concatenated at the end. In this case you'll need to
|
||||
modify startup.S to copy modules out of bss to let's say ALIGN_UP (_end, 8)
|
||||
before cleaning out bss. You'll probably find useful to add total_module_size
|
||||
before cleaning out bss. You'll probably find it useful to add total_module_size
|
||||
field to startup.S. In init.c you need to set grub_modbase to the address
|
||||
where modules can be found. You may need grub_modules_get_end () to avoid
|
||||
declaring the space occupied by modules as usable for heap. You can test modules
|
||||
@ -1164,9 +1214,9 @@ Once this works, you should think of implementing disk access. Look around
|
||||
disk/ for examples.
|
||||
|
||||
Then, very importantly, you probably need to implement the actual loader
|
||||
(examples available in loader/)
|
||||
(examples available in loader/).
|
||||
|
||||
Last step to have minimally usable port is to add support to grub-install to
|
||||
The last step to have a minimally usable port is to add support to grub-install to
|
||||
put GRUB in a place where firmware or platform will pick it up.
|
||||
|
||||
Next steps are: filling datetime.c, setjmp.S, network (net/drivers),
|
||||
@ -1175,15 +1225,15 @@ video (video/), halt (lib/), reboot (lib/).
|
||||
Please add your platform to Platform limitations and Supported kernels chapter
|
||||
in user documentation and mention any steps you skipped which result in reduced
|
||||
features or performance. Here is the quick checklist of features. Some of them
|
||||
are less important than others and skipping them is completely ok, just needs
|
||||
are less important than others and skipping them is completely ok, it just needs
|
||||
to be mentioned in user documentation.
|
||||
|
||||
Checklist:
|
||||
@itemize
|
||||
@item Is heap big enough?
|
||||
@item Which charset is supported by console?
|
||||
@item Does platform have disk driver?
|
||||
@item Do you have network card support?
|
||||
@item Is the heap big enough?
|
||||
@item Which charset is supported by the console?
|
||||
@item Does the platform have disk driver?
|
||||
@item Is there network card support?
|
||||
@item Are you able to retrieve datetime (with date)?
|
||||
@item Are you able to set datetime (with date)?
|
||||
@item Is serial supported?
|
||||
@ -1209,16 +1259,16 @@ GRUB?
|
||||
@node Error Handling
|
||||
@chapter Error Handling
|
||||
|
||||
Error handling in GRUB 2 is based on exception handling model. As C language
|
||||
Error handling in GRUB 2 is based on exception handling model. As the C language
|
||||
doesn't directly support exceptions, exception handling behavior is emulated
|
||||
in software.
|
||||
in software.
|
||||
|
||||
When exception is raised, function must return to calling function. If calling
|
||||
When an exception is raised, the function must return to the calling function. If the calling
|
||||
function does not provide handling of the exception it must return back to its
|
||||
calling function and so on, until exception is handled. If exception is not
|
||||
handled before prompt is displayed, error message will be shown to user.
|
||||
calling function and so on, until the exception is handled. If the exception is not
|
||||
handled before a prompt is displayed, error message will be shown to user.
|
||||
|
||||
Exception information is stored on @code{grub_errno} global variable. If
|
||||
Exception information is stored in the @code{grub_errno} global variable. If
|
||||
@code{grub_errno} variable contains value @code{GRUB_ERR_NONE}, there is no active
|
||||
exception and application can continue normal processing. When @code{grub_errno} has
|
||||
other value, it is required that application code either handles this error or
|
||||
|
||||
925
docs/grub.texi
925
docs/grub.texi
File diff suppressed because it is too large
Load Diff
@ -246,6 +246,8 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/alloc.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/ieee1275.h
|
||||
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/platform_keystore.h
|
||||
endif
|
||||
|
||||
if COND_sparc64_ieee1275
|
||||
|
||||
@ -248,6 +248,7 @@ kernel = {
|
||||
xen = term/xen/console.c;
|
||||
xen = disk/xen/xendisk.c;
|
||||
xen = commands/boot.c;
|
||||
xen = kern/xen/cmdline.c;
|
||||
|
||||
i386_xen_pvh = commands/boot.c;
|
||||
i386_xen_pvh = disk/xen/xendisk.c;
|
||||
@ -255,6 +256,7 @@ kernel = {
|
||||
i386_xen_pvh = kern/i386/xen/tsc.c;
|
||||
i386_xen_pvh = kern/i386/xen/pvh.c;
|
||||
i386_xen_pvh = kern/xen/init.c;
|
||||
i386_xen_pvh = kern/xen/cmdline.c;
|
||||
i386_xen_pvh = term/xen/console.c;
|
||||
|
||||
ia64_efi = kern/ia64/efi/startup.S;
|
||||
@ -331,6 +333,9 @@ kernel = {
|
||||
powerpc_ieee1275 = kern/powerpc/cache.S;
|
||||
powerpc_ieee1275 = kern/powerpc/dl.c;
|
||||
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
|
||||
powerpc_ieee1275 = kern/lockdown.c;
|
||||
powerpc_ieee1275 = kern/powerpc/ieee1275/ieee1275.c;
|
||||
powerpc_ieee1275 = kern/powerpc/ieee1275/platform_keystore.c;
|
||||
|
||||
sparc64_ieee1275 = kern/sparc64/cache.S;
|
||||
sparc64_ieee1275 = kern/sparc64/dl.c;
|
||||
@ -367,6 +372,9 @@ kernel = {
|
||||
emu = kern/emu/cache_s.S;
|
||||
emu = kern/emu/hostdisk.c;
|
||||
emu = osdep/unix/hostdisk.c;
|
||||
emu = osdep/relpath.c;
|
||||
emu = osdep/getroot.c;
|
||||
emu = osdep/unix/getroot.c;
|
||||
emu = osdep/exec.c;
|
||||
extra_dist = osdep/unix/exec.c;
|
||||
emu = osdep/devmapper/hostdisk.c;
|
||||
@ -845,6 +853,18 @@ module = {
|
||||
common = commands/blocklist.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = blsuki;
|
||||
common = commands/blsuki.c;
|
||||
common = lib/gnulib/filevercmp.c;
|
||||
enable = powerpc_ieee1275;
|
||||
enable = efi;
|
||||
enable = i386_pc;
|
||||
enable = emu;
|
||||
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
|
||||
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = boot;
|
||||
common = commands/boot.c;
|
||||
@ -979,6 +999,21 @@ module = {
|
||||
cppflags = '$(CPPFLAGS_GCRY)';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = appendedsig;
|
||||
common = commands/appendedsig/appendedsig.c;
|
||||
common = commands/appendedsig/x509.c;
|
||||
common = commands/appendedsig/pkcs7.c;
|
||||
common = commands/appendedsig/asn1util.c;
|
||||
common = commands/appendedsig/gnutls_asn1_tab.c;
|
||||
common = commands/appendedsig/pkix_asn1_tab.c;
|
||||
enable = emu;
|
||||
enable = powerpc_ieee1275;
|
||||
cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls';
|
||||
cppflags = '$(CPPFLAGS_GCRY) -I$(srcdir)/lib/libtasn1-grub';
|
||||
depends = crypto, gcry_rsa, gcry_sha256, gcry_sha512, mpi, asn1;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = hdparm;
|
||||
common = commands/hdparm.c;
|
||||
@ -1685,6 +1720,8 @@ module = {
|
||||
module = {
|
||||
name = crypto;
|
||||
common = lib/crypto.c;
|
||||
common = lib/hwfeatures-gcry.c;
|
||||
x86_64_efi = lib/x86_64/efi/hwfeatures-gcry.c;
|
||||
|
||||
extra_dist = lib/libgcrypt-grub/cipher/crypto.lst;
|
||||
};
|
||||
@ -1694,6 +1731,11 @@ module = {
|
||||
common = lib/pbkdf2.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = argon2;
|
||||
common = lib/argon2.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = relocator;
|
||||
common = lib/relocator.c;
|
||||
@ -2196,6 +2238,14 @@ module = {
|
||||
cppflags = '$(CPPFLAGS_GCRY)';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = appended_signature_test;
|
||||
common = tests/appended_signature_test.c;
|
||||
common = tests/appended_signatures.h;
|
||||
enable = emu;
|
||||
enable = powerpc_ieee1275;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = signature_test;
|
||||
common = tests/signature_test.c;
|
||||
@ -2217,6 +2267,16 @@ module = {
|
||||
common = tests/pbkdf2_test.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = argon2_test;
|
||||
common = tests/argon2_test.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = crypto_cipher_mode_test;
|
||||
common = tests/crypto_cipher_mode_test.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = legacy_password_test;
|
||||
common = tests/legacy_password_test.c;
|
||||
@ -2469,6 +2529,13 @@ module = {
|
||||
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = zstdio;
|
||||
common = io/zstdio.c;
|
||||
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/zstd';
|
||||
cflags='-Wno-unreachable-code';
|
||||
};
|
||||
|
||||
module = {
|
||||
name = testload;
|
||||
common = commands/testload.c;
|
||||
|
||||
@ -50,6 +50,12 @@ grub_memmove (void *dest, const void *src, grub_size_t n)
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *
|
||||
grub_memcpy (void *dest, const void *src, grub_size_t n)
|
||||
{
|
||||
return grub_memmove (dest, src, n);
|
||||
}
|
||||
|
||||
int
|
||||
grub_memcmp (const void *s1, const void *s2, grub_size_t n)
|
||||
{
|
||||
|
||||
1716
grub-core/commands/appendedsig/appendedsig.c
Normal file
1716
grub-core/commands/appendedsig/appendedsig.c
Normal file
File diff suppressed because it is too large
Load Diff
133
grub-core/commands/appendedsig/appendedsig.h
Normal file
133
grub-core/commands/appendedsig/appendedsig.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2020, 2022, 2025 IBM Corporation
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/crypto.h>
|
||||
#include <libtasn1.h>
|
||||
|
||||
extern asn1_node grub_gnutls_gnutls_asn;
|
||||
extern asn1_node grub_gnutls_pkix_asn;
|
||||
|
||||
#define GRUB_MAX_OID_LEN 32
|
||||
|
||||
/* RSA public key. */
|
||||
#define GRUB_MAX_MPI 2
|
||||
#define GRUB_RSA_PK_MODULUS 0
|
||||
#define GRUB_RSA_PK_EXPONENT 1
|
||||
|
||||
/* Certificate fingerprint. */
|
||||
#define GRUB_MAX_FINGERPRINT 3
|
||||
#define GRUB_FINGERPRINT_SHA256 0
|
||||
#define GRUB_FINGERPRINT_SHA384 1
|
||||
#define GRUB_FINGERPRINT_SHA512 2
|
||||
|
||||
/* Max size of hash data. */
|
||||
#define GRUB_MAX_HASH_LEN 64
|
||||
|
||||
/*
|
||||
* One or more x509 certificates. We do limited parsing:
|
||||
* extracting only the version, serial, issuer, subject, RSA public key
|
||||
* and key size.
|
||||
* Also, hold the sha256, sha384, and sha512 fingerprint of the certificate.
|
||||
*/
|
||||
struct x509_certificate
|
||||
{
|
||||
struct x509_certificate *next;
|
||||
grub_uint8_t version;
|
||||
grub_uint8_t *serial;
|
||||
grub_size_t serial_len;
|
||||
char *issuer;
|
||||
grub_size_t issuer_len;
|
||||
char *subject;
|
||||
grub_size_t subject_len;
|
||||
/* We only support RSA public keys. This encodes [modulus, publicExponent]. */
|
||||
gcry_mpi_t mpis[GRUB_MAX_MPI];
|
||||
grub_int32_t modulus_size;
|
||||
grub_uint8_t fingerprint[GRUB_MAX_FINGERPRINT][GRUB_MAX_HASH_LEN];
|
||||
};
|
||||
typedef struct x509_certificate grub_x509_cert_t;
|
||||
|
||||
/* A PKCS#7 signed data signer info. */
|
||||
struct pkcs7_signer
|
||||
{
|
||||
const gcry_md_spec_t *hash;
|
||||
gcry_mpi_t sig_mpi;
|
||||
};
|
||||
typedef struct pkcs7_signer grub_pkcs7_signer_t;
|
||||
|
||||
/*
|
||||
* A PKCS#7 signed data message. We make no attempt to match intelligently, so
|
||||
* we don't save any info about the signer.
|
||||
*/
|
||||
struct pkcs7_data
|
||||
{
|
||||
grub_int32_t signer_count;
|
||||
grub_pkcs7_signer_t *signers;
|
||||
};
|
||||
typedef struct pkcs7_data grub_pkcs7_data_t;
|
||||
|
||||
/*
|
||||
* Import a DER-encoded certificate at 'data', of size 'size'. Place the results
|
||||
* into 'results', which must be already allocated.
|
||||
*/
|
||||
extern grub_err_t
|
||||
grub_x509_cert_parse (const void *data, grub_size_t size, grub_x509_cert_t *results);
|
||||
|
||||
/*
|
||||
* Release all the storage associated with the x509 certificate. If the caller
|
||||
* dynamically allocated the certificate, it must free it. The caller is also
|
||||
* responsible for maintenance of the linked list.
|
||||
*/
|
||||
extern void
|
||||
grub_x509_cert_release (grub_x509_cert_t *cert);
|
||||
|
||||
/*
|
||||
* Parse a PKCS#7 message, which must be a signed data message. The message must
|
||||
* be in 'sigbuf' and of size 'data_size'. The result is placed in 'msg', which
|
||||
* must already be allocated.
|
||||
*/
|
||||
extern grub_err_t
|
||||
grub_pkcs7_data_parse (const void *sigbuf, grub_size_t data_size, grub_pkcs7_data_t *msg);
|
||||
|
||||
/*
|
||||
* Release all the storage associated with the PKCS#7 message. If the caller
|
||||
* dynamically allocated the message, it must free it.
|
||||
*/
|
||||
extern void
|
||||
grub_pkcs7_data_release (grub_pkcs7_data_t *msg);
|
||||
|
||||
/* Do libtasn1 init. */
|
||||
extern int
|
||||
grub_asn1_init (void);
|
||||
|
||||
/*
|
||||
* Read a value from an ASN1 node, allocating memory to store it. It will work
|
||||
* for anything where the size libtasn1 returns is right:
|
||||
* - Integers
|
||||
* - Octet strings
|
||||
* - DER encoding of other structures
|
||||
*
|
||||
* It will _not_ work for things where libtasn1 size requires adjustment:
|
||||
* - Strings that require an extra null byte at the end
|
||||
* - Bit strings because libtasn1 returns the length in bits, not bytes.
|
||||
*
|
||||
* If the function returns a non-NULL value, the caller must free it.
|
||||
*/
|
||||
extern void *
|
||||
grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name,
|
||||
grub_int32_t *content_size);
|
||||
99
grub-core/commands/appendedsig/asn1util.c
Normal file
99
grub-core/commands/appendedsig/asn1util.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2020, 2022, 2025 IBM Corporation
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libtasn1.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gcrypt/gcrypt.h>
|
||||
|
||||
#include "appendedsig.h"
|
||||
|
||||
asn1_node grub_gnutls_gnutls_asn = NULL;
|
||||
asn1_node grub_gnutls_pkix_asn = NULL;
|
||||
|
||||
extern const asn1_static_node grub_gnutls_asn1_tab[];
|
||||
extern const asn1_static_node grub_pkix_asn1_tab[];
|
||||
|
||||
/*
|
||||
* Read a value from an ASN1 node, allocating memory to store it. It will work
|
||||
* for anything where the size libtasn1 returns is right:
|
||||
* - Integers
|
||||
* - Octet strings
|
||||
* - DER encoding of other structures
|
||||
*
|
||||
* It will _not_ work for things where libtasn1 size requires adjustment:
|
||||
* - Strings that require an extra NULL byte at the end
|
||||
* - Bit strings because libtasn1 returns the length in bits, not bytes.
|
||||
*
|
||||
* If the function returns a non-NULL value, the caller must free it.
|
||||
*/
|
||||
void *
|
||||
grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name,
|
||||
grub_int32_t *content_size)
|
||||
{
|
||||
grub_int32_t result;
|
||||
grub_uint8_t *tmpstr = NULL;
|
||||
grub_int32_t tmpstr_size = 0;
|
||||
|
||||
result = asn1_read_value (node, name, NULL, &tmpstr_size);
|
||||
if (result != ASN1_MEM_ERROR)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FILE_TYPE, "reading size of %s did not return expected status: %s",
|
||||
friendly_name, asn1_strerror (result)) ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmpstr = grub_malloc (tmpstr_size);
|
||||
if (tmpstr == NULL)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not allocate memory to store %s",
|
||||
friendly_name) ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = asn1_read_value (node, name, tmpstr, &tmpstr_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
grub_free (tmpstr);
|
||||
grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading %s: %s", friendly_name,
|
||||
asn1_strerror (result)) ;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*content_size = tmpstr_size;
|
||||
|
||||
return tmpstr;
|
||||
}
|
||||
|
||||
int
|
||||
grub_asn1_init (void)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = asn1_array2tree (grub_gnutls_asn1_tab, &grub_gnutls_gnutls_asn, NULL);
|
||||
if (res != ASN1_SUCCESS)
|
||||
return res;
|
||||
|
||||
res = asn1_array2tree (grub_pkix_asn1_tab, &grub_gnutls_pkix_asn, NULL);
|
||||
|
||||
return res;
|
||||
}
|
||||
148
grub-core/commands/appendedsig/gnutls_asn1_tab.c
Normal file
148
grub-core/commands/appendedsig/gnutls_asn1_tab.c
Normal file
@ -0,0 +1,148 @@
|
||||
#include <grub/mm.h>
|
||||
#include <libtasn1.h>
|
||||
|
||||
/*
|
||||
* Imported from gnutls.asn.
|
||||
* https://github.com/gnutls/gnutls/blob/master/lib/gnutls.asn
|
||||
*/
|
||||
const asn1_static_node grub_gnutls_asn1_tab[] = {
|
||||
{ "GNUTLS", 536872976, NULL },
|
||||
{ NULL, 1073741836, NULL },
|
||||
{ "RSAPublicKey", 1610612741, NULL },
|
||||
{ "modulus", 1073741827, NULL },
|
||||
{ "publicExponent", 3, NULL },
|
||||
{ "RSAPrivateKey", 1610612741, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "modulus", 1073741827, NULL },
|
||||
{ "publicExponent", 1073741827, NULL },
|
||||
{ "privateExponent", 1073741827, NULL },
|
||||
{ "prime1", 1073741827, NULL },
|
||||
{ "prime2", 1073741827, NULL },
|
||||
{ "exponent1", 1073741827, NULL },
|
||||
{ "exponent2", 1073741827, NULL },
|
||||
{ "coefficient", 1073741827, NULL },
|
||||
{ "otherPrimeInfos", 16386, "OtherPrimeInfos"},
|
||||
{ "ProvableSeed", 1610612741, NULL },
|
||||
{ "algorithm", 1073741836, NULL },
|
||||
{ "seed", 7, NULL },
|
||||
{ "OtherPrimeInfos", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "OtherPrimeInfo"},
|
||||
{ "OtherPrimeInfo", 1610612741, NULL },
|
||||
{ "prime", 1073741827, NULL },
|
||||
{ "exponent", 1073741827, NULL },
|
||||
{ "coefficient", 3, NULL },
|
||||
{ "AlgorithmIdentifier", 1610612741, NULL },
|
||||
{ "algorithm", 1073741836, NULL },
|
||||
{ "parameters", 541081613, NULL },
|
||||
{ "algorithm", 1, NULL },
|
||||
{ "DigestInfo", 1610612741, NULL },
|
||||
{ "digestAlgorithm", 1073741826, "DigestAlgorithmIdentifier"},
|
||||
{ "digest", 7, NULL },
|
||||
{ "DigestAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "DSAPublicKey", 1073741827, NULL },
|
||||
{ "DSAParameters", 1610612741, NULL },
|
||||
{ "p", 1073741827, NULL },
|
||||
{ "q", 1073741827, NULL },
|
||||
{ "g", 3, NULL },
|
||||
{ "DSASignatureValue", 1610612741, NULL },
|
||||
{ "r", 1073741827, NULL },
|
||||
{ "s", 3, NULL },
|
||||
{ "DSAPrivateKey", 1610612741, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "p", 1073741827, NULL },
|
||||
{ "q", 1073741827, NULL },
|
||||
{ "g", 1073741827, NULL },
|
||||
{ "Y", 1073741827, NULL },
|
||||
{ "priv", 3, NULL },
|
||||
{ "DHParameter", 1610612741, NULL },
|
||||
{ "prime", 1073741827, NULL },
|
||||
{ "base", 1073741827, NULL },
|
||||
{ "privateValueLength", 16387, NULL },
|
||||
{ "pkcs-11-ec-Parameters", 1610612754, NULL },
|
||||
{ "oId", 1073741836, NULL },
|
||||
{ "curveName", 31, NULL },
|
||||
{ "ECParameters", 1610612754, NULL },
|
||||
{ "namedCurve", 12, NULL },
|
||||
{ "ECPrivateKey", 1610612741, NULL },
|
||||
{ "Version", 1073741827, NULL },
|
||||
{ "privateKey", 1073741831, NULL },
|
||||
{ "parameters", 1610637314, "ECParameters"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "publicKey", 536895494, NULL },
|
||||
{ NULL, 2056, "1"},
|
||||
{ "PrincipalName", 1610612741, NULL },
|
||||
{ "name-type", 1610620931, NULL },
|
||||
{ NULL, 2056, "0"},
|
||||
{ "name-string", 536879115, NULL },
|
||||
{ NULL, 1073743880, "1"},
|
||||
{ NULL, 27, NULL },
|
||||
{ "KRB5PrincipalName", 1610612741, NULL },
|
||||
{ "realm", 1610620955, NULL },
|
||||
{ NULL, 2056, "0"},
|
||||
{ "principalName", 536879106, "PrincipalName"},
|
||||
{ NULL, 2056, "1"},
|
||||
{ "RSAPSSParameters", 1610612741, NULL },
|
||||
{ "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
|
||||
{ NULL, 2056, "1"},
|
||||
{ "saltLength", 1610653699, NULL },
|
||||
{ NULL, 1073741833, "20"},
|
||||
{ NULL, 2056, "2"},
|
||||
{ "trailerField", 536911875, NULL },
|
||||
{ NULL, 1073741833, "1"},
|
||||
{ NULL, 2056, "3"},
|
||||
{ "RSAOAEPParameters", 1610612741, NULL },
|
||||
{ "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
|
||||
{ NULL, 2056, "1"},
|
||||
{ "pSourceFunc", 536895490, "AlgorithmIdentifier"},
|
||||
{ NULL, 2056, "2"},
|
||||
{ "GOSTParameters", 1610612741, NULL },
|
||||
{ "publicKeyParamSet", 1073741836, NULL },
|
||||
{ "digestParamSet", 16396, NULL },
|
||||
{ "GOSTParametersOld", 1610612741, NULL },
|
||||
{ "publicKeyParamSet", 1073741836, NULL },
|
||||
{ "digestParamSet", 1073741836, NULL },
|
||||
{ "encryptionParamSet", 16396, NULL },
|
||||
{ "GOSTPrivateKey", 1073741831, NULL },
|
||||
{ "GOSTPrivateKeyOld", 1073741827, NULL },
|
||||
{ "IssuerSignTool", 1610612741, NULL },
|
||||
{ "signTool", 1073741858, NULL },
|
||||
{ "cATool", 1073741858, NULL },
|
||||
{ "signToolCert", 1073741858, NULL },
|
||||
{ "cAToolCert", 34, NULL },
|
||||
{ "Gost28147-89-EncryptedKey", 1610612741, NULL },
|
||||
{ "encryptedKey", 1073741831, NULL },
|
||||
{ "maskKey", 1610637319, NULL },
|
||||
{ NULL, 4104, "0"},
|
||||
{ "macKey", 7, NULL },
|
||||
{ "SubjectPublicKeyInfo", 1610612741, NULL },
|
||||
{ "algorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "subjectPublicKey", 6, NULL },
|
||||
{ "GostR3410-TransportParameters", 1610612741, NULL },
|
||||
{ "encryptionParamSet", 1073741836, NULL },
|
||||
{ "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "ukm", 7, NULL },
|
||||
{ "GostR3410-KeyTransport", 1610612741, NULL },
|
||||
{ "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
|
||||
{ "transportParameters", 536895490, "GostR3410-TransportParameters"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "TPMKey", 1610612741, NULL },
|
||||
{ "type", 1073741836, NULL },
|
||||
{ "emptyAuth", 1610637316, NULL },
|
||||
{ NULL, 2056, "0"},
|
||||
{ "parent", 1073741827, NULL },
|
||||
{ "pubkey", 1073741831, NULL },
|
||||
{ "privkey", 7, NULL },
|
||||
{ "MLDSAPrivateKey", 536870917, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "privateKey", 1073741831, NULL },
|
||||
{ "publicKey", 536895495, NULL },
|
||||
{ NULL, 2056, "1"},
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
452
grub-core/commands/appendedsig/pkcs7.c
Normal file
452
grub-core/commands/appendedsig/pkcs7.c
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2020, 2022, 2025 IBM Corporation
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "appendedsig.h"
|
||||
#include <grub/misc.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/gcrypt/gcrypt.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
|
||||
|
||||
/* RFC 5652 s 5.1. */
|
||||
static const char *signedData_oid = "1.2.840.113549.1.7.2";
|
||||
|
||||
/* RFC 4055 s 2.1. */
|
||||
static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
|
||||
static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
|
||||
|
||||
static grub_err_t
|
||||
process_content (grub_uint8_t *content, grub_int32_t size, grub_pkcs7_data_t *msg)
|
||||
{
|
||||
grub_int32_t res;
|
||||
asn1_node signed_part;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
char algo_oid[GRUB_MAX_OID_LEN];
|
||||
grub_int32_t algo_oid_size;
|
||||
grub_int32_t algo_count;
|
||||
grub_int32_t signer_count;
|
||||
grub_int32_t i;
|
||||
char version;
|
||||
grub_int32_t version_size = sizeof (version);
|
||||
grub_uint8_t *result_buf;
|
||||
grub_int32_t result_size = 0;
|
||||
grub_int32_t crls_size = 0;
|
||||
gcry_error_t gcry_err;
|
||||
bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
|
||||
char *da_path;
|
||||
char *si_sig_path;
|
||||
char *si_da_path;
|
||||
|
||||
res = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", &signed_part);
|
||||
if (res != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not create ASN.1 structure for PKCS#7 signed part");
|
||||
|
||||
res = asn1_der_decoding2 (&signed_part, content, &size,
|
||||
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"error reading PKCS#7 signed data: %s", asn1_error);
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
/*
|
||||
* SignedData ::= SEQUENCE {
|
||||
* version CMSVersion,
|
||||
* digestAlgorithms DigestAlgorithmIdentifiers,
|
||||
* encapContentInfo EncapsulatedContentInfo,
|
||||
* certificates [0] IMPLICIT CertificateSet OPTIONAL,
|
||||
* crls [1] IMPLICIT RevocationInfoChoices OPTIONAL,
|
||||
* signerInfos SignerInfos }
|
||||
*/
|
||||
|
||||
res = asn1_read_value (signed_part, "version", &version, &version_size);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading signedData version: %s",
|
||||
asn1_strerror (res));
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
/* Signature version must be 1 because appended signature only support v1. */
|
||||
if (version != 1)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"unexpected signature version v%d, only v1 supported", version);
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
/*
|
||||
* digestAlgorithms DigestAlgorithmIdentifiers
|
||||
*
|
||||
* DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
|
||||
* DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
|
||||
*
|
||||
* RFC 4055 s 2.1:
|
||||
* sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL }
|
||||
* sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL }
|
||||
*
|
||||
* We only support 1 element in the set, and we do not check parameters atm.
|
||||
*/
|
||||
res = asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error counting number of digest algorithms: %s",
|
||||
asn1_strerror (res));
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
if (algo_count <= 0)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "a minimum of 1 digest algorithm is required");
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
if (algo_count > 2)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "a maximum of 2 digest algorithms is supported");
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
sha256_in_da = false;
|
||||
sha512_in_da = false;
|
||||
|
||||
for (i = 0; i < algo_count; i++)
|
||||
{
|
||||
da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1);
|
||||
if (da_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate path for digest algorithm parsing path");
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
algo_oid_size = sizeof (algo_oid);
|
||||
res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading digest algorithm: %s",
|
||||
asn1_strerror (res));
|
||||
grub_free (da_path);
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
|
||||
{
|
||||
if (sha512_in_da == false)
|
||||
sha512_in_da = true;
|
||||
else
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"SHA-512 specified twice in digest algorithm list");
|
||||
grub_free (da_path);
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
}
|
||||
else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
|
||||
{
|
||||
if (sha256_in_da == false)
|
||||
sha256_in_da = true;
|
||||
else
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"SHA-256 specified twice in digest algorithm list");
|
||||
grub_free (da_path);
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"only SHA-256 and SHA-512 hashes are supported, found OID %s",
|
||||
algo_oid);
|
||||
grub_free (da_path);
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
grub_free (da_path);
|
||||
}
|
||||
|
||||
/* At this point, at least one of sha{256,512}_in_da must be true. */
|
||||
|
||||
/*
|
||||
* We ignore the certificates, but we don't permit CRLs. A CRL entry might be
|
||||
* revoking the certificate we're using, and we have no way of dealing with
|
||||
* that at the moment.
|
||||
*/
|
||||
res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
|
||||
if (res != ASN1_ELEMENT_NOT_FOUND)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"PKCS#7 messages with embedded CRLs are not supported");
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
/* Read the signatures */
|
||||
res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error counting number of signers: %s",
|
||||
asn1_strerror (res));
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
if (signer_count <= 0)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "a minimum of 1 signer is required");
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
msg->signers = grub_calloc (signer_count, sizeof (grub_pkcs7_signer_t));
|
||||
if (msg->signers == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate space for %d signers", signer_count);
|
||||
goto cleanup_signed_part;
|
||||
}
|
||||
|
||||
msg->signer_count = 0;
|
||||
for (i = 0; i < signer_count; i++)
|
||||
{
|
||||
si_da_path = grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
|
||||
if (si_da_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate path for signer %d's digest algorithm parsing path",
|
||||
i);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
algo_oid_size = sizeof (algo_oid);
|
||||
res = asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"error reading signer %d's digest algorithm: %s", i, asn1_strerror (res));
|
||||
grub_free (si_da_path);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
grub_free (si_da_path);
|
||||
|
||||
if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
|
||||
{
|
||||
if (sha512_in_da == false)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"signer %d claims a SHA-512 signature which was not "
|
||||
"specified in the outer DigestAlgorithms", i);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
else
|
||||
{
|
||||
sha512_in_si = true;
|
||||
msg->signers[i].hash = grub_crypto_lookup_md_by_name ("sha512");
|
||||
}
|
||||
}
|
||||
else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
|
||||
{
|
||||
if (sha256_in_da == false)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"signer %d claims a SHA-256 signature which was not "
|
||||
"specified in the outer DigestAlgorithms", i);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
else
|
||||
{
|
||||
sha256_in_si = true;
|
||||
msg->signers[i].hash = grub_crypto_lookup_md_by_name ("sha256");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"only SHA-256 and SHA-512 hashes are supported, found OID %s",
|
||||
algo_oid);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
if (msg->signers[i].hash == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"Hash algorithm for signer %d (OID %s) not loaded", i, algo_oid);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1);
|
||||
if (si_sig_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate path for signer %d's signature parsing path", i);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
result_buf = grub_asn1_allocate_and_read (signed_part, si_sig_path, "signature data", &result_size);
|
||||
grub_free (si_sig_path);
|
||||
|
||||
if (result_buf == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
gcry_err = _gcry_mpi_scan (&(msg->signers[i].sig_mpi), GCRYMPI_FMT_USG,
|
||||
result_buf, result_size, NULL);
|
||||
grub_free (result_buf);
|
||||
|
||||
if (gcry_err != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"error loading signature %d into MPI structure: %d",
|
||||
i, gcry_err);
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
/*
|
||||
* Use msg->signer_count to track fully populated signerInfos so we know
|
||||
* how many we need to clean up.
|
||||
*/
|
||||
msg->signer_count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Final consistency check of signerInfo.*.digestAlgorithm vs digestAlgorithms
|
||||
* .*.algorithm. An algorithm must be present in both digestAlgorithms and
|
||||
* signerInfo or in neither. We have already checked for an algorithm in
|
||||
* signerInfo that is not in digestAlgorithms, here we check for algorithms in
|
||||
* digestAlgorithms but not in signerInfos.
|
||||
*/
|
||||
if (sha512_in_da == true && sha512_in_si == false)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"SHA-512 specified in DigestAlgorithms but did not appear in SignerInfos");
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
if (sha256_in_da == true && sha256_in_si == false)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"SHA-256 specified in DigestAlgorithms but did not appear in SignerInfos");
|
||||
goto cleanup_signerInfos;
|
||||
}
|
||||
|
||||
asn1_delete_structure (&signed_part);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
cleanup_signerInfos:
|
||||
for (i = 0; i < msg->signer_count; i++)
|
||||
_gcry_mpi_release (msg->signers[i].sig_mpi);
|
||||
|
||||
grub_free (msg->signers);
|
||||
|
||||
cleanup_signed_part:
|
||||
asn1_delete_structure (&signed_part);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_pkcs7_data_parse (const void *sigbuf, grub_size_t data_size, grub_pkcs7_data_t *msg)
|
||||
{
|
||||
grub_int32_t res;
|
||||
asn1_node content_info;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
char content_oid[GRUB_MAX_OID_LEN];
|
||||
grub_uint8_t *content;
|
||||
grub_int32_t content_size;
|
||||
grub_int32_t content_oid_size = sizeof (content_oid);
|
||||
grub_int32_t size = (grub_int32_t) data_size;
|
||||
|
||||
if (data_size > GRUB_UINT_MAX)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"cannot parse a PKCS#7 message where data size > GRUB_UINT_MAX");
|
||||
|
||||
res = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.pkcs-7-ContentInfo", &content_info);
|
||||
if (res != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not create ASN.1 structure for PKCS#7 data: %s",
|
||||
asn1_strerror (res));
|
||||
|
||||
res = asn1_der_decoding2 (&content_info, sigbuf, &size,
|
||||
ASN1_DECODE_FLAG_STRICT_DER | ASN1_DECODE_FLAG_ALLOW_PADDING,
|
||||
asn1_error);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"error decoding PKCS#7 message DER: %s", asn1_error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* ContentInfo ::= SEQUENCE {
|
||||
* contentType ContentType,
|
||||
* content [0] EXPLICIT ANY DEFINED BY contentType }
|
||||
*
|
||||
* ContentType ::= OBJECT IDENTIFIER
|
||||
*/
|
||||
res = asn1_read_value (content_info, "contentType", content_oid, &content_oid_size);
|
||||
if (res != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading PKCS#7 content type: %s",
|
||||
asn1_strerror (res));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* OID for SignedData defined in 5.1. */
|
||||
if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_SIGNATURE,
|
||||
"unexpected content type in PKCS#7 message: OID %s", content_oid);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
content = grub_asn1_allocate_and_read (content_info, "content", "PKCS#7 message content", &content_size);
|
||||
if (content == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = process_content (content, content_size, msg);
|
||||
grub_free (content);
|
||||
|
||||
cleanup:
|
||||
asn1_delete_structure (&content_info);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release all the storage associated with the PKCS#7 message. If the caller
|
||||
* dynamically allocated the message, it must free it.
|
||||
*/
|
||||
void
|
||||
grub_pkcs7_data_release (grub_pkcs7_data_t *msg)
|
||||
{
|
||||
grub_int32_t i;
|
||||
|
||||
for (i = 0; i < msg->signer_count; i++)
|
||||
_gcry_mpi_release (msg->signers[i].sig_mpi);
|
||||
|
||||
grub_free (msg->signers);
|
||||
}
|
||||
485
grub-core/commands/appendedsig/pkix_asn1_tab.c
Normal file
485
grub-core/commands/appendedsig/pkix_asn1_tab.c
Normal file
@ -0,0 +1,485 @@
|
||||
#include <grub/mm.h>
|
||||
#include <libtasn1.h>
|
||||
|
||||
/*
|
||||
* Imported from pkix.asn.
|
||||
* https://github.com/gnutls/gnutls/blob/master/lib/pkix.asn
|
||||
*/
|
||||
const asn1_static_node grub_pkix_asn1_tab[] = {
|
||||
{ "PKIX1", 536875024, NULL },
|
||||
{ NULL, 1073741836, NULL },
|
||||
{ "PrivateKeyUsagePeriod", 1610612741, NULL },
|
||||
{ "notBefore", 1610637349, NULL },
|
||||
{ NULL, 4104, "0"},
|
||||
{ "notAfter", 536895525, NULL },
|
||||
{ NULL, 4104, "1"},
|
||||
{ "AuthorityKeyIdentifier", 1610612741, NULL },
|
||||
{ "keyIdentifier", 1610637319, NULL },
|
||||
{ NULL, 4104, "0"},
|
||||
{ "authorityCertIssuer", 1610637314, "GeneralNames"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "authorityCertSerialNumber", 536895490, "CertificateSerialNumber"},
|
||||
{ NULL, 4104, "2"},
|
||||
{ "SubjectKeyIdentifier", 1073741831, NULL },
|
||||
{ "KeyUsage", 1073741830, NULL },
|
||||
{ "DirectoryString", 1610612754, NULL },
|
||||
{ "teletexString", 1612709918, NULL },
|
||||
{ "MAX", 524298, "1"},
|
||||
{ "printableString", 1612709919, NULL },
|
||||
{ "MAX", 524298, "1"},
|
||||
{ "universalString", 1612709920, NULL },
|
||||
{ "MAX", 524298, "1"},
|
||||
{ "utf8String", 1612709922, NULL },
|
||||
{ "MAX", 524298, "1"},
|
||||
{ "bmpString", 538968097, NULL },
|
||||
{ "MAX", 524298, "1"},
|
||||
{ "SubjectAltName", 1073741826, "GeneralNames"},
|
||||
{ "GeneralNames", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "GeneralName"},
|
||||
{ "GeneralName", 1610612754, NULL },
|
||||
{ "otherName", 1610620930, "AnotherName"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "rfc822Name", 1610620957, NULL },
|
||||
{ NULL, 4104, "1"},
|
||||
{ "dNSName", 1610620957, NULL },
|
||||
{ NULL, 4104, "2"},
|
||||
{ "x400Address", 1610620941, NULL },
|
||||
{ NULL, 4104, "3"},
|
||||
{ "directoryName", 1610620939, NULL },
|
||||
{ NULL, 1073743880, "4"},
|
||||
{ NULL, 2, "RelativeDistinguishedName"},
|
||||
{ "ediPartyName", 1610620941, NULL },
|
||||
{ NULL, 4104, "5"},
|
||||
{ "uniformResourceIdentifier", 1610620957, NULL },
|
||||
{ NULL, 4104, "6"},
|
||||
{ "iPAddress", 1610620935, NULL },
|
||||
{ NULL, 4104, "7"},
|
||||
{ "registeredID", 536879116, NULL },
|
||||
{ NULL, 4104, "8"},
|
||||
{ "AnotherName", 1610612741, NULL },
|
||||
{ "type-id", 1073741836, NULL },
|
||||
{ "value", 541073421, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ "type-id", 1, NULL },
|
||||
{ "IssuerAltName", 1073741826, "GeneralNames"},
|
||||
{ "BasicConstraints", 1610612741, NULL },
|
||||
{ "cA", 1610645508, NULL },
|
||||
{ NULL, 131081, NULL },
|
||||
{ "pathLenConstraint", 16387, NULL },
|
||||
{ "CRLDistributionPoints", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "DistributionPoint"},
|
||||
{ "DistributionPoint", 1610612741, NULL },
|
||||
{ "distributionPoint", 1610637314, "DistributionPointName"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "reasons", 1610637314, "ReasonFlags"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "cRLIssuer", 536895490, "GeneralNames"},
|
||||
{ NULL, 4104, "2"},
|
||||
{ "DistributionPointName", 1610612754, NULL },
|
||||
{ "fullName", 1610620930, "GeneralNames"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "nameRelativeToCRLIssuer", 536879106, "RelativeDistinguishedName"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "ReasonFlags", 1073741830, NULL },
|
||||
{ "ExtKeyUsageSyntax", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 12, NULL },
|
||||
{ "AuthorityInfoAccessSyntax", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "AccessDescription"},
|
||||
{ "AccessDescription", 1610612741, NULL },
|
||||
{ "accessMethod", 1073741836, NULL },
|
||||
{ "accessLocation", 2, "GeneralName"},
|
||||
{ "Attribute", 1610612741, NULL },
|
||||
{ "type", 1073741836, NULL },
|
||||
{ "values", 536870927, NULL },
|
||||
{ NULL, 13, NULL },
|
||||
{ "AttributeTypeAndValue", 1610612741, NULL },
|
||||
{ "type", 1073741836, NULL },
|
||||
{ "value", 13, NULL },
|
||||
{ "Name", 1610612754, NULL },
|
||||
{ "rdnSequence", 536870923, NULL },
|
||||
{ NULL, 2, "RelativeDistinguishedName"},
|
||||
{ "DistinguishedName", 1610612747, NULL },
|
||||
{ NULL, 2, "RelativeDistinguishedName"},
|
||||
{ "RelativeDistinguishedName", 1612709903, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "AttributeTypeAndValue"},
|
||||
{ "Certificate", 1610612741, NULL },
|
||||
{ "tbsCertificate", 1073741826, "TBSCertificate"},
|
||||
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "signature", 6, NULL },
|
||||
{ "TBSCertificate", 1610612741, NULL },
|
||||
{ "version", 1610653699, NULL },
|
||||
{ NULL, 1073741833, "0"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "serialNumber", 1073741826, "CertificateSerialNumber"},
|
||||
{ "signature", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "issuer", 1073741826, "Name"},
|
||||
{ "validity", 1073741826, "Validity"},
|
||||
{ "subject", 1073741826, "Name"},
|
||||
{ "subjectPublicKeyInfo", 1073741826, "SubjectPublicKeyInfo"},
|
||||
{ "issuerUniqueID", 1610637314, "UniqueIdentifier"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "subjectUniqueID", 1610637314, "UniqueIdentifier"},
|
||||
{ NULL, 4104, "2"},
|
||||
{ "extensions", 536895490, "Extensions"},
|
||||
{ NULL, 2056, "3"},
|
||||
{ "CertificateSerialNumber", 1073741827, NULL },
|
||||
{ "Validity", 1610612741, NULL },
|
||||
{ "notBefore", 1073741826, "Time"},
|
||||
{ "notAfter", 2, "Time"},
|
||||
{ "Time", 1610612754, NULL },
|
||||
{ "utcTime", 1073741860, NULL },
|
||||
{ "generalTime", 37, NULL },
|
||||
{ "UniqueIdentifier", 1073741830, NULL },
|
||||
{ "SubjectPublicKeyInfo", 1610612741, NULL },
|
||||
{ "algorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "subjectPublicKey", 6, NULL },
|
||||
{ "Extensions", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "Extension"},
|
||||
{ "Extension", 1610612741, NULL },
|
||||
{ "extnID", 1073741836, NULL },
|
||||
{ "critical", 1610645508, NULL },
|
||||
{ NULL, 131081, NULL },
|
||||
{ "extnValue", 7, NULL },
|
||||
{ "CertificateList", 1610612741, NULL },
|
||||
{ "tbsCertList", 1073741826, "TBSCertList"},
|
||||
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "signature", 6, NULL },
|
||||
{ "TBSCertList", 1610612741, NULL },
|
||||
{ "version", 1073758211, NULL },
|
||||
{ "signature", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "issuer", 1073741826, "Name"},
|
||||
{ "thisUpdate", 1073741826, "Time"},
|
||||
{ "nextUpdate", 1073758210, "Time"},
|
||||
{ "revokedCertificates", 1610629131, NULL },
|
||||
{ NULL, 536870917, NULL },
|
||||
{ "userCertificate", 1073741826, "CertificateSerialNumber"},
|
||||
{ "revocationDate", 1073741826, "Time"},
|
||||
{ "crlEntryExtensions", 16386, "Extensions"},
|
||||
{ "crlExtensions", 536895490, "Extensions"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "AlgorithmIdentifier", 1610612741, NULL },
|
||||
{ "algorithm", 1073741836, NULL },
|
||||
{ "parameters", 541081613, NULL },
|
||||
{ "algorithm", 1, NULL },
|
||||
{ "Dss-Sig-Value", 1610612741, NULL },
|
||||
{ "r", 1073741827, NULL },
|
||||
{ "s", 3, NULL },
|
||||
{ "Dss-Parms", 1610612741, NULL },
|
||||
{ "p", 1073741827, NULL },
|
||||
{ "q", 1073741827, NULL },
|
||||
{ "g", 3, NULL },
|
||||
{ "pkcs-7-ContentInfo", 1610612741, NULL },
|
||||
{ "contentType", 1073741836, NULL },
|
||||
{ "content", 541073421, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ "contentType", 1, NULL },
|
||||
{ "pkcs-7-DigestInfo", 1610612741, NULL },
|
||||
{ "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "digest", 7, NULL },
|
||||
{ "pkcs-7-SignedData", 1610612741, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "digestAlgorithms", 1073741826, "pkcs-7-DigestAlgorithmIdentifiers"},
|
||||
{ "encapContentInfo", 1073741826, "pkcs-7-EncapsulatedContentInfo"},
|
||||
{ "certificates", 1610637314, "pkcs-7-CertificateSet"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "crls", 1610637314, "pkcs-7-CertificateRevocationLists"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "signerInfos", 2, "pkcs-7-SignerInfos"},
|
||||
{ "pkcs-7-DigestAlgorithmIdentifiers", 1610612751, NULL },
|
||||
{ NULL, 2, "AlgorithmIdentifier"},
|
||||
{ "pkcs-7-EncapsulatedContentInfo", 1610612741, NULL },
|
||||
{ "eContentType", 1073741836, NULL },
|
||||
{ "eContent", 536895501, NULL },
|
||||
{ NULL, 2056, "0"},
|
||||
{ "pkcs-7-CertificateRevocationLists", 1610612751, NULL },
|
||||
{ NULL, 13, NULL },
|
||||
{ "pkcs-7-CertificateChoices", 1610612754, NULL },
|
||||
{ "certificate", 13, NULL },
|
||||
{ "pkcs-7-CertificateSet", 1610612751, NULL },
|
||||
{ NULL, 2, "pkcs-7-CertificateChoices"},
|
||||
{ "IssuerAndSerialNumber", 1610612741, NULL },
|
||||
{ "issuer", 1073741826, "Name"},
|
||||
{ "serialNumber", 2, "CertificateSerialNumber"},
|
||||
{ "pkcs-7-SignerInfo", 1610612741, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "sid", 1073741826, "SignerIdentifier"},
|
||||
{ "digestAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "signedAttrs", 1610637314, "SignedAttributes"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "signature", 1073741831, NULL },
|
||||
{ "unsignedAttrs", 536895490, "SignedAttributes"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "SignedAttributes", 1612709903, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "Attribute"},
|
||||
{ "SignerIdentifier", 1610612754, NULL },
|
||||
{ "issuerAndSerialNumber", 1073741826, "IssuerAndSerialNumber"},
|
||||
{ "subjectKeyIdentifier", 536879111, NULL },
|
||||
{ NULL, 4104, "0"},
|
||||
{ "pkcs-7-SignerInfos", 1610612751, NULL },
|
||||
{ NULL, 2, "pkcs-7-SignerInfo"},
|
||||
{ "pkcs-10-CertificationRequestInfo", 1610612741, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "subject", 1073741826, "Name"},
|
||||
{ "subjectPKInfo", 1073741826, "SubjectPublicKeyInfo"},
|
||||
{ "attributes", 536879106, "Attributes"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "Attributes", 1610612751, NULL },
|
||||
{ NULL, 2, "Attribute"},
|
||||
{ "pkcs-10-CertificationRequest", 1610612741, NULL },
|
||||
{ "certificationRequestInfo", 1073741826, "pkcs-10-CertificationRequestInfo"},
|
||||
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "signature", 6, NULL },
|
||||
{ "pkcs-9-at-challengePassword", 1879048204, NULL },
|
||||
{ "iso", 1073741825, "1"},
|
||||
{ "member-body", 1073741825, "2"},
|
||||
{ "us", 1073741825, "840"},
|
||||
{ "rsadsi", 1073741825, "113549"},
|
||||
{ "pkcs", 1073741825, "1"},
|
||||
{ NULL, 1073741825, "9"},
|
||||
{ NULL, 1, "7"},
|
||||
{ "pkcs-9-challengePassword", 1610612754, NULL },
|
||||
{ "printableString", 1073741855, NULL },
|
||||
{ "utf8String", 34, NULL },
|
||||
{ "pkcs-9-localKeyId", 1073741831, NULL },
|
||||
{ "pkcs-8-PrivateKeyInfo", 1610612741, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "privateKey", 1073741831, NULL },
|
||||
{ "attributes", 536895490, "Attributes"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "pkcs-8-EncryptedPrivateKeyInfo", 1610612741, NULL },
|
||||
{ "encryptionAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "encryptedData", 2, "pkcs-8-EncryptedData"},
|
||||
{ "pkcs-8-EncryptedData", 1073741831, NULL },
|
||||
{ "pkcs-5-des-CBC-params", 1612709895, NULL },
|
||||
{ NULL, 1048586, "8"},
|
||||
{ "pkcs-5-des-EDE3-CBC-params", 1612709895, NULL },
|
||||
{ NULL, 1048586, "8"},
|
||||
{ "pkcs-5-aes128-CBC-params", 1612709895, NULL },
|
||||
{ NULL, 1048586, "16"},
|
||||
{ "pkcs-5-aes192-CBC-params", 1612709895, NULL },
|
||||
{ NULL, 1048586, "16"},
|
||||
{ "pkcs-5-aes256-CBC-params", 1612709895, NULL },
|
||||
{ NULL, 1048586, "16"},
|
||||
{ "Gost28147-89-Parameters", 1610612741, NULL },
|
||||
{ "iv", 1073741831, NULL },
|
||||
{ "encryptionParamSet", 12, NULL },
|
||||
{ "pkcs-5-PBE-params", 1610612741, NULL },
|
||||
{ "salt", 1073741831, NULL },
|
||||
{ "iterationCount", 3, NULL },
|
||||
{ "pkcs-5-PBES2-params", 1610612741, NULL },
|
||||
{ "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "encryptionScheme", 2, "AlgorithmIdentifier"},
|
||||
{ "pkcs-5-PBMAC1-params", 1610612741, NULL },
|
||||
{ "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "messageAuthScheme", 2, "AlgorithmIdentifier"},
|
||||
{ "pkcs-5-PBKDF2-params", 1610612741, NULL },
|
||||
{ "salt", 1610612754, NULL },
|
||||
{ "specified", 1073741831, NULL },
|
||||
{ "otherSource", 2, "AlgorithmIdentifier"},
|
||||
{ "iterationCount", 1073741827, NULL },
|
||||
{ "keyLength", 1073758211, NULL },
|
||||
{ "prf", 16386, "AlgorithmIdentifier"},
|
||||
{ "pkcs-12-PFX", 1610612741, NULL },
|
||||
{ "version", 1610874883, NULL },
|
||||
{ "v3", 1, "3"},
|
||||
{ "authSafe", 1073741826, "pkcs-7-ContentInfo"},
|
||||
{ "macData", 16386, "pkcs-12-MacData"},
|
||||
{ "pkcs-12-PbeParams", 1610612741, NULL },
|
||||
{ "salt", 1073741831, NULL },
|
||||
{ "iterations", 3, NULL },
|
||||
{ "pkcs-12-MacData", 1610612741, NULL },
|
||||
{ "mac", 1073741826, "pkcs-7-DigestInfo"},
|
||||
{ "macSalt", 1073741831, NULL },
|
||||
{ "iterations", 536903683, NULL },
|
||||
{ NULL, 9, "1"},
|
||||
{ "pkcs-12-AuthenticatedSafe", 1610612747, NULL },
|
||||
{ NULL, 2, "pkcs-7-ContentInfo"},
|
||||
{ "pkcs-12-SafeContents", 1610612747, NULL },
|
||||
{ NULL, 2, "pkcs-12-SafeBag"},
|
||||
{ "pkcs-12-SafeBag", 1610612741, NULL },
|
||||
{ "bagId", 1073741836, NULL },
|
||||
{ "bagValue", 1614815245, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ "badId", 1, NULL },
|
||||
{ "bagAttributes", 536887311, NULL },
|
||||
{ NULL, 2, "Attribute"},
|
||||
{ "pkcs-12-CertBag", 1610612741, NULL },
|
||||
{ "certId", 1073741836, NULL },
|
||||
{ "certValue", 541073421, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ "certId", 1, NULL },
|
||||
{ "pkcs-12-CRLBag", 1610612741, NULL },
|
||||
{ "crlId", 1073741836, NULL },
|
||||
{ "crlValue", 541073421, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ "crlId", 1, NULL },
|
||||
{ "pkcs-12-SecretBag", 1610612741, NULL },
|
||||
{ "secretTypeId", 1073741836, NULL },
|
||||
{ "secretValue", 541073421, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ "secretTypeId", 1, NULL },
|
||||
{ "pkcs-7-Data", 1073741831, NULL },
|
||||
{ "pkcs-7-EncryptedData", 1610612741, NULL },
|
||||
{ "version", 1073741827, NULL },
|
||||
{ "encryptedContentInfo", 1073741826, "pkcs-7-EncryptedContentInfo"},
|
||||
{ "unprotectedAttrs", 536895490, "pkcs-7-UnprotectedAttributes"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "pkcs-7-EncryptedContentInfo", 1610612741, NULL },
|
||||
{ "contentType", 1073741836, NULL },
|
||||
{ "contentEncryptionAlgorithm", 1073741826, "pkcs-7-ContentEncryptionAlgorithmIdentifier"},
|
||||
{ "encryptedContent", 536895495, NULL },
|
||||
{ NULL, 4104, "0"},
|
||||
{ "pkcs-7-ContentEncryptionAlgorithmIdentifier", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "pkcs-7-UnprotectedAttributes", 1612709903, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "Attribute"},
|
||||
{ "ProxyCertInfo", 1610612741, NULL },
|
||||
{ "pCPathLenConstraint", 1073758211, NULL },
|
||||
{ "proxyPolicy", 2, "ProxyPolicy"},
|
||||
{ "ProxyPolicy", 1610612741, NULL },
|
||||
{ "policyLanguage", 1073741836, NULL },
|
||||
{ "policy", 16391, NULL },
|
||||
{ "certificatePolicies", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "PolicyInformation"},
|
||||
{ "PolicyInformation", 1610612741, NULL },
|
||||
{ "policyIdentifier", 1073741836, NULL },
|
||||
{ "policyQualifiers", 538984459, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "PolicyQualifierInfo"},
|
||||
{ "PolicyQualifierInfo", 1610612741, NULL },
|
||||
{ "policyQualifierId", 1073741836, NULL },
|
||||
{ "qualifier", 541065229, NULL },
|
||||
{ "policyQualifierId", 1, NULL },
|
||||
{ "CPSuri", 1073741853, NULL },
|
||||
{ "UserNotice", 1610612741, NULL },
|
||||
{ "noticeRef", 1073758210, "NoticeReference"},
|
||||
{ "explicitText", 16386, "DisplayText"},
|
||||
{ "NoticeReference", 1610612741, NULL },
|
||||
{ "organization", 1073741826, "DisplayText"},
|
||||
{ "noticeNumbers", 536870923, NULL },
|
||||
{ NULL, 3, NULL },
|
||||
{ "DisplayText", 1610612754, NULL },
|
||||
{ "ia5String", 1612709917, NULL },
|
||||
{ "200", 524298, "1"},
|
||||
{ "visibleString", 1612709923, NULL },
|
||||
{ "200", 524298, "1"},
|
||||
{ "bmpString", 1612709921, NULL },
|
||||
{ "200", 524298, "1"},
|
||||
{ "utf8String", 538968098, NULL },
|
||||
{ "200", 524298, "1"},
|
||||
{ "OCSPRequest", 1610612741, NULL },
|
||||
{ "tbsRequest", 1073741826, "TBSRequest"},
|
||||
{ "optionalSignature", 536895490, "Signature"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "TBSRequest", 1610612741, NULL },
|
||||
{ "version", 1610653699, NULL },
|
||||
{ NULL, 1073741833, "0"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "requestorName", 1610637314, "GeneralName"},
|
||||
{ NULL, 2056, "1"},
|
||||
{ "requestList", 1610612747, NULL },
|
||||
{ NULL, 2, "Request"},
|
||||
{ "requestExtensions", 536895490, "Extensions"},
|
||||
{ NULL, 2056, "2"},
|
||||
{ "Signature", 1610612741, NULL },
|
||||
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "signature", 1073741830, NULL },
|
||||
{ "certs", 536895499, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ NULL, 2, "Certificate"},
|
||||
{ "Request", 1610612741, NULL },
|
||||
{ "reqCert", 1073741826, "CertID"},
|
||||
{ "singleRequestExtensions", 536895490, "Extensions"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "CertID", 1610612741, NULL },
|
||||
{ "hashAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "issuerNameHash", 1073741831, NULL },
|
||||
{ "issuerKeyHash", 1073741831, NULL },
|
||||
{ "serialNumber", 2, "CertificateSerialNumber"},
|
||||
{ "OCSPResponse", 1610612741, NULL },
|
||||
{ "responseStatus", 1073741826, "OCSPResponseStatus"},
|
||||
{ "responseBytes", 536895490, "ResponseBytes"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "OCSPResponseStatus", 1610874901, NULL },
|
||||
{ "successful", 1073741825, "0"},
|
||||
{ "malformedRequest", 1073741825, "1"},
|
||||
{ "internalError", 1073741825, "2"},
|
||||
{ "tryLater", 1073741825, "3"},
|
||||
{ "sigRequired", 1073741825, "5"},
|
||||
{ "unauthorized", 1, "6"},
|
||||
{ "ResponseBytes", 1610612741, NULL },
|
||||
{ "responseType", 1073741836, NULL },
|
||||
{ "response", 7, NULL },
|
||||
{ "BasicOCSPResponse", 1610612741, NULL },
|
||||
{ "tbsResponseData", 1073741826, "ResponseData"},
|
||||
{ "signatureAlgorithm", 1073741826, "AlgorithmIdentifier"},
|
||||
{ "signature", 1073741830, NULL },
|
||||
{ "certs", 536895499, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ NULL, 2, "Certificate"},
|
||||
{ "ResponseData", 1610612741, NULL },
|
||||
{ "version", 1610653699, NULL },
|
||||
{ NULL, 1073741833, "0"},
|
||||
{ NULL, 2056, "0"},
|
||||
{ "responderID", 1073741826, "ResponderID"},
|
||||
{ "producedAt", 1073741861, NULL },
|
||||
{ "responses", 1610612747, NULL },
|
||||
{ NULL, 2, "SingleResponse"},
|
||||
{ "responseExtensions", 536895490, "Extensions"},
|
||||
{ NULL, 2056, "1"},
|
||||
{ "ResponderID", 1610612754, NULL },
|
||||
{ "byName", 1610620939, NULL },
|
||||
{ NULL, 1073743880, "1"},
|
||||
{ NULL, 2, "RelativeDistinguishedName"},
|
||||
{ "byKey", 536879111, NULL },
|
||||
{ NULL, 2056, "2"},
|
||||
{ "SingleResponse", 1610612741, NULL },
|
||||
{ "certID", 1073741826, "CertID"},
|
||||
{ "certStatus", 1073741826, "CertStatus"},
|
||||
{ "thisUpdate", 1073741861, NULL },
|
||||
{ "nextUpdate", 1610637349, NULL },
|
||||
{ NULL, 2056, "0"},
|
||||
{ "singleExtensions", 536895490, "Extensions"},
|
||||
{ NULL, 2056, "1"},
|
||||
{ "CertStatus", 1610612754, NULL },
|
||||
{ "good", 1610620948, NULL },
|
||||
{ NULL, 4104, "0"},
|
||||
{ "revoked", 1610620930, "RevokedInfo"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "unknown", 536879106, "UnknownInfo"},
|
||||
{ NULL, 4104, "2"},
|
||||
{ "RevokedInfo", 1610612741, NULL },
|
||||
{ "revocationTime", 1073741861, NULL },
|
||||
{ "revocationReason", 537157653, NULL },
|
||||
{ NULL, 1073743880, "0"},
|
||||
{ "unspecified", 1, "0"},
|
||||
{ "UnknownInfo", 1073741844, NULL },
|
||||
{ "NameConstraints", 1610612741, NULL },
|
||||
{ "permittedSubtrees", 1610637314, "GeneralSubtrees"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "excludedSubtrees", 536895490, "GeneralSubtrees"},
|
||||
{ NULL, 4104, "1"},
|
||||
{ "GeneralSubtrees", 1612709899, NULL },
|
||||
{ "MAX", 1074266122, "1"},
|
||||
{ NULL, 2, "GeneralSubtree"},
|
||||
{ "GeneralSubtree", 1610612741, NULL },
|
||||
{ "base", 1073741826, "GeneralName"},
|
||||
{ "minimum", 1610653699, NULL },
|
||||
{ NULL, 1073741833, "0"},
|
||||
{ NULL, 4104, "0"},
|
||||
{ "maximum", 536895491, NULL },
|
||||
{ NULL, 4104, "1"},
|
||||
{ "TlsFeatures", 536870923, NULL },
|
||||
{ NULL, 3, NULL },
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
970
grub-core/commands/appendedsig/x509.c
Normal file
970
grub-core/commands/appendedsig/x509.c
Normal file
@ -0,0 +1,970 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2020, 2022, 2025 IBM Corporation
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libtasn1.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/gcrypt/gcrypt.h>
|
||||
|
||||
#include "appendedsig.h"
|
||||
|
||||
static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
|
||||
|
||||
|
||||
/* RFC 3279 2.3.1 RSA Keys. */
|
||||
static const char *rsaEncryption_oid = "1.2.840.113549.1.1.1";
|
||||
|
||||
/* RFC 5280 Appendix A. */
|
||||
static const char *commonName_oid = "2.5.4.3";
|
||||
|
||||
/* RFC 5280 4.2.1.3 Key Usage. */
|
||||
static const char *keyUsage_oid = "2.5.29.15";
|
||||
|
||||
static const grub_uint8_t digitalSignatureUsage = 0x80;
|
||||
|
||||
/* RFC 5280 4.2.1.9 Basic Constraints. */
|
||||
static const char *basicConstraints_oid = "2.5.29.19";
|
||||
|
||||
/* RFC 5280 4.2.1.12 Extended Key Usage. */
|
||||
static const char *extendedKeyUsage_oid = "2.5.29.37";
|
||||
static const char *codeSigningUsage_oid = "1.3.6.1.5.5.7.3.3";
|
||||
|
||||
/*
|
||||
* RFC 3279 2.3.1
|
||||
*
|
||||
* The RSA public key MUST be encoded using the ASN.1 type RSAPublicKey:
|
||||
*
|
||||
* RSAPublicKey ::= SEQUENCE {
|
||||
* modulus INTEGER, -- n
|
||||
* publicExponent INTEGER } -- e
|
||||
*
|
||||
* where modulus is the modulus n, and publicExponent is the public exponent e.
|
||||
*/
|
||||
static grub_err_t
|
||||
grub_parse_rsa_pubkey (grub_uint8_t *der, grub_int32_t dersize, grub_x509_cert_t *certificate)
|
||||
{
|
||||
grub_int32_t result;
|
||||
asn1_node spk = NULL;
|
||||
grub_uint8_t *m_data, *e_data;
|
||||
grub_int32_t m_size, e_size;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
gcry_error_t gcry_err;
|
||||
|
||||
result = asn1_create_element (grub_gnutls_gnutls_asn, "GNUTLS.RSAPublicKey", &spk);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"cannot create storage for public key ASN.1 data");
|
||||
|
||||
result = asn1_der_decoding2 (&spk, der, &dersize, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"cannot decode certificate public key DER: %s", asn1_error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
m_data = grub_asn1_allocate_and_read (spk, "modulus", "RSA modulus", &m_size);
|
||||
if (m_data == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
e_data = grub_asn1_allocate_and_read (spk, "publicExponent", "RSA public exponent", &e_size);
|
||||
if (e_data == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup_m_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert m, e to mpi
|
||||
*
|
||||
* nscanned is not set for FMT_USG, it's only set for FMT_PGP, so we can't
|
||||
* verify it.
|
||||
*/
|
||||
gcry_err = _gcry_mpi_scan (&certificate->mpis[0], GCRYMPI_FMT_USG, m_data, m_size, NULL);
|
||||
if (gcry_err != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"error loading RSA modulus into MPI structure: %d", gcry_err);
|
||||
goto cleanup_e_data;
|
||||
}
|
||||
|
||||
gcry_err = _gcry_mpi_scan (&certificate->mpis[1], GCRYMPI_FMT_USG, e_data, e_size, NULL);
|
||||
if (gcry_err != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"error loading RSA exponent into MPI structure: %d", gcry_err);
|
||||
goto cleanup_m_mpi;
|
||||
}
|
||||
|
||||
/* RSA key size in bits. */
|
||||
certificate->modulus_size = (m_size * 8) - 8;
|
||||
|
||||
grub_free (e_data);
|
||||
grub_free (m_data);
|
||||
asn1_delete_structure (&spk);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
cleanup_m_mpi:
|
||||
_gcry_mpi_release (certificate->mpis[0]);
|
||||
cleanup_e_data:
|
||||
grub_free (e_data);
|
||||
cleanup_m_data:
|
||||
grub_free (m_data);
|
||||
cleanup:
|
||||
asn1_delete_structure (&spk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 5280:
|
||||
* SubjectPublicKeyInfo ::= SEQUENCE {
|
||||
* algorithm AlgorithmIdentifier,
|
||||
* subjectPublicKey BIT STRING }
|
||||
*
|
||||
* AlgorithmIdentifiers come from RFC 3279, we are not strictly compilant as we
|
||||
* only support RSA Encryption.
|
||||
*/
|
||||
static grub_err_t
|
||||
grub_x509_read_subject_public_key (asn1_node asn, grub_x509_cert_t *results)
|
||||
{
|
||||
grub_int32_t result;
|
||||
grub_err_t err;
|
||||
const char *algo_name = "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm";
|
||||
const char *params_name = "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters";
|
||||
const char *pk_name = "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey";
|
||||
char algo_oid[GRUB_MAX_OID_LEN];
|
||||
grub_int32_t algo_size = sizeof (algo_oid);
|
||||
char params_value[2];
|
||||
grub_int32_t params_size = sizeof (params_value);
|
||||
grub_uint8_t *key_data = NULL;
|
||||
grub_int32_t key_size = 0;
|
||||
grub_uint32_t key_type;
|
||||
|
||||
/* Algorithm: see notes for rsaEncryption_oid. */
|
||||
result = asn1_read_value (asn, algo_name, algo_oid, &algo_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading x509 public key algorithm: %s",
|
||||
asn1_strerror (result));
|
||||
|
||||
if (grub_strncmp (algo_oid, rsaEncryption_oid, sizeof (rsaEncryption_oid)) != 0)
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unsupported x509 public key algorithm: %s", algo_oid);
|
||||
|
||||
/*
|
||||
* RFC 3279 2.3.1 : The rsaEncryption OID is intended to be used in the
|
||||
* algorithm field of a value of type AlgorithmIdentifier. The parameters
|
||||
* field MUST have ASN.1 type NULL for this algorithm identifier.
|
||||
*/
|
||||
result = asn1_read_value (asn, params_name, params_value, ¶ms_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading x509 public key parameters: %s",
|
||||
asn1_strerror (result));
|
||||
|
||||
if (params_value[0] != ASN1_TAG_NULL)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"invalid x509 public key parameters: expected NULL");
|
||||
|
||||
/*
|
||||
* RFC 3279 2.3.1: The DER encoded RSAPublicKey is the value of the BIT
|
||||
* STRING subjectPublicKey.
|
||||
*/
|
||||
result = asn1_read_value_type (asn, pk_name, NULL, &key_size, &key_type);
|
||||
if (result != ASN1_MEM_ERROR)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading size of x509 public key: %s",
|
||||
asn1_strerror (result));
|
||||
if (key_type != ASN1_ETYPE_BIT_STRING)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "unexpected ASN.1 type when reading x509 public key: %x",
|
||||
key_type);
|
||||
|
||||
/* Length is in bits. */
|
||||
key_size = (key_size + 7) / 8;
|
||||
|
||||
key_data = grub_malloc (key_size);
|
||||
if (key_data == NULL)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory for x509 public key");
|
||||
|
||||
result = asn1_read_value (asn, pk_name, key_data, &key_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
grub_free (key_data);
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading public key data");
|
||||
}
|
||||
|
||||
key_size = (key_size + 7) / 8;
|
||||
err = grub_parse_rsa_pubkey (key_data, key_size, results);
|
||||
grub_free (key_data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Decode a string as defined in Appendix A. */
|
||||
static grub_err_t
|
||||
decode_string (char *der, grub_int32_t der_size, char **string, grub_size_t *string_size)
|
||||
{
|
||||
asn1_node strasn;
|
||||
grub_int32_t result;
|
||||
char *choice;
|
||||
grub_int32_t choice_size = 0;
|
||||
grub_int32_t tmp_size = 0;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
|
||||
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.DirectoryString", &strasn);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not create ASN.1 structure for certificate: %s",
|
||||
asn1_strerror (result));
|
||||
|
||||
result = asn1_der_decoding2 (&strasn, der, &der_size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"could not parse DER for DirectoryString: %s", asn1_error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
choice = grub_asn1_allocate_and_read (strasn, "", "DirectoryString choice", &choice_size);
|
||||
if (choice == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (grub_strncmp ("utf8String", choice, choice_size) == 0)
|
||||
{
|
||||
result = asn1_read_value (strasn, "utf8String", NULL, &tmp_size);
|
||||
if (result != ASN1_MEM_ERROR)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading size of UTF-8 string: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup_choice;
|
||||
}
|
||||
}
|
||||
else if (grub_strncmp ("printableString", choice, choice_size) == 0)
|
||||
{
|
||||
result = asn1_read_value (strasn, "printableString", NULL, &tmp_size);
|
||||
if (result != ASN1_MEM_ERROR)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading size of printableString: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup_choice;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"only UTF-8 and printable DirectoryStrings are supported, got %s",
|
||||
choice);
|
||||
goto cleanup_choice;
|
||||
}
|
||||
|
||||
/* Read size does not include trailing NUL. */
|
||||
tmp_size++;
|
||||
|
||||
*string = grub_malloc (tmp_size);
|
||||
if (*string == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"cannot allocate memory for DirectoryString contents");
|
||||
goto cleanup_choice;
|
||||
}
|
||||
|
||||
result = asn1_read_value (strasn, choice, *string, &tmp_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading out %s in DirectoryString: %s",
|
||||
choice, asn1_strerror (result));
|
||||
grub_free (*string);
|
||||
*string = NULL;
|
||||
goto cleanup_choice;
|
||||
}
|
||||
|
||||
*string_size = tmp_size + 1;
|
||||
(*string)[tmp_size] = '\0';
|
||||
|
||||
cleanup_choice:
|
||||
grub_free (choice);
|
||||
cleanup:
|
||||
asn1_delete_structure (&strasn);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* TBSCertificate ::= SEQUENCE {
|
||||
* version [0] EXPLICIT Version DEFAULT v1,
|
||||
* ...
|
||||
*
|
||||
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
|
||||
*/
|
||||
static grub_err_t
|
||||
check_version (asn1_node certificate, grub_x509_cert_t *results)
|
||||
{
|
||||
grub_int32_t rc;
|
||||
const char *name = "tbsCertificate.version";
|
||||
grub_uint8_t version;
|
||||
grub_int32_t len = sizeof (version);
|
||||
|
||||
rc = asn1_read_value (certificate, name, &version, &len);
|
||||
|
||||
/* Require version 3. */
|
||||
if (rc != ASN1_SUCCESS || len != 1)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading certificate version");
|
||||
|
||||
if (version != 0x02)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"invalid x509 certificate version, expected v3 (0x02), got 0x%02x.",
|
||||
version);
|
||||
|
||||
results->version = version;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* we extract only the CN and issuer. */
|
||||
static grub_err_t
|
||||
read_name (asn1_node asn, const char *name_path, char **name, grub_size_t *name_size)
|
||||
{
|
||||
grub_int32_t seq_components, set_components;
|
||||
grub_int32_t result;
|
||||
grub_int32_t i, j;
|
||||
char *top_path, *set_path, *type_path, *val_path;
|
||||
char type[GRUB_MAX_OID_LEN];
|
||||
grub_int32_t type_len = sizeof (type);
|
||||
grub_int32_t string_size = 0;
|
||||
char *string_der;
|
||||
grub_err_t err;
|
||||
|
||||
*name = NULL;
|
||||
|
||||
top_path = grub_xasprintf ("%s.rdnSequence", name_path);
|
||||
if (top_path == NULL)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate memory for %s name parsing path", name_path);
|
||||
|
||||
result = asn1_number_of_elements (asn, top_path, &seq_components);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error counting name components: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 1; i <= seq_components; i++)
|
||||
{
|
||||
set_path = grub_xasprintf ("%s.?%d", top_path, i);
|
||||
if (set_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate memory for %s name set parsing path",
|
||||
name_path);
|
||||
goto cleanup_set;
|
||||
}
|
||||
/* This brings us, hopefully, to a set. */
|
||||
result = asn1_number_of_elements (asn, set_path, &set_components);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"error counting name sub-components components (element %d): %s",
|
||||
i, asn1_strerror (result));
|
||||
goto cleanup_set;
|
||||
}
|
||||
for (j = 1; j <= set_components; j++)
|
||||
{
|
||||
type_path = grub_xasprintf ("%s.?%d.?%d.type", top_path, i, j);
|
||||
if (type_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate memory for %s name component type path",
|
||||
name_path);
|
||||
goto cleanup_set;
|
||||
}
|
||||
type_len = sizeof (type);
|
||||
result = asn1_read_value (asn, type_path, type, &type_len);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading %s name component type: %s",
|
||||
name_path, asn1_strerror (result));
|
||||
goto cleanup_type;
|
||||
}
|
||||
|
||||
if (grub_strncmp (type, commonName_oid, type_len) != 0)
|
||||
{
|
||||
grub_free (type_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
val_path = grub_xasprintf ("%s.?%d.?%d.value", top_path, i, j);
|
||||
if (val_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not allocate memory for %s name component value path",
|
||||
name_path);
|
||||
goto cleanup_type;
|
||||
}
|
||||
|
||||
string_der = grub_asn1_allocate_and_read (asn, val_path, name_path, &string_size);
|
||||
if (string_der == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup_val_path;
|
||||
}
|
||||
|
||||
err = decode_string (string_der, string_size, name, name_size);
|
||||
if (err)
|
||||
goto cleanup_string;
|
||||
|
||||
grub_free (string_der);
|
||||
grub_free (type_path);
|
||||
grub_free (val_path);
|
||||
break;
|
||||
}
|
||||
|
||||
grub_free (set_path);
|
||||
if (*name)
|
||||
break;
|
||||
}
|
||||
|
||||
grub_free (top_path);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
cleanup_string:
|
||||
grub_free (string_der);
|
||||
cleanup_val_path:
|
||||
grub_free (val_path);
|
||||
cleanup_type:
|
||||
grub_free (type_path);
|
||||
cleanup_set:
|
||||
grub_free (set_path);
|
||||
cleanup:
|
||||
grub_free (top_path);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Verify the Key Usage extension. We require the Digital Signature usage. */
|
||||
static grub_err_t
|
||||
verify_key_usage (grub_uint8_t *value, grub_int32_t value_size)
|
||||
{
|
||||
asn1_node usageasn;
|
||||
grub_int32_t result;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
grub_uint8_t usage = 0xff;
|
||||
grub_int32_t usage_size = sizeof (usage_size);
|
||||
|
||||
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.KeyUsage", &usageasn);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not create ASN.1 structure for key usage");
|
||||
|
||||
result = asn1_der_decoding2 (&usageasn, value, &value_size,
|
||||
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"error parsing DER for Key Usage: %s", asn1_error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = asn1_read_value (usageasn, "", &usage, &usage_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading Key Usage value: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(usage & digitalSignatureUsage))
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"key usage (0x%x) missing Digital Signature usage", usage);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
asn1_delete_structure (&usageasn);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* BasicConstraints ::= SEQUENCE {
|
||||
* cA BOOLEAN DEFAULT FALSE,
|
||||
* pathLenConstraint INTEGER (0..MAX) OPTIONAL }
|
||||
*/
|
||||
static grub_err_t
|
||||
verify_basic_constraints (grub_uint8_t *value, grub_int32_t value_size)
|
||||
{
|
||||
asn1_node basicasn;
|
||||
grub_int32_t result;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
char cA[6]; /* FALSE or TRUE. */
|
||||
grub_int32_t cA_size = sizeof (cA);
|
||||
|
||||
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.BasicConstraints", &basicasn);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not create ASN.1 structure for Basic Constraints");
|
||||
|
||||
result = asn1_der_decoding2 (&basicasn, value, &value_size,
|
||||
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"error parsing DER for Basic Constraints: %s", asn1_error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
result = asn1_read_value (basicasn, "cA", cA, &cA_size);
|
||||
if (result == ASN1_ELEMENT_NOT_FOUND)
|
||||
{
|
||||
/* Not present, default is False, so this is OK. */
|
||||
err = GRUB_ERR_NONE;
|
||||
goto cleanup;
|
||||
}
|
||||
else if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading Basic Constraints cA value: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* The certificate must not be a CA certificate. */
|
||||
if (grub_strncmp ("FALSE", cA, cA_size) != 0)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "unexpected CA value: %s", cA);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
asn1_delete_structure (&basicasn);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the Extended Key Usage extension. We require the Code Signing usage.
|
||||
*
|
||||
* ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
|
||||
*
|
||||
* KeyPurposeId ::= OBJECT IDENTIFIER
|
||||
*/
|
||||
static grub_err_t
|
||||
verify_extended_key_usage (grub_uint8_t *value, grub_int32_t value_size)
|
||||
{
|
||||
asn1_node extendedasn;
|
||||
grub_int32_t result, count, i = 0;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
char usage[GRUB_MAX_OID_LEN], name[3];
|
||||
grub_int32_t usage_size = sizeof (usage);
|
||||
|
||||
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.ExtKeyUsageSyntax", &extendedasn);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not create ASN.1 structure for Extended Key Usage");
|
||||
|
||||
result = asn1_der_decoding2 (&extendedasn, value, &value_size,
|
||||
ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"error parsing DER for Extended Key Usage: %s", asn1_error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* If EKUs are present, it checks the presents of Code Signing usage. */
|
||||
result = asn1_number_of_elements (extendedasn, "", &count);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error counting number of Extended Key Usages: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 1; i < count + 1; i++)
|
||||
{
|
||||
grub_memset (name, 0, sizeof (name));
|
||||
grub_snprintf (name, sizeof (name), "?%d", i);
|
||||
result = asn1_read_value (extendedasn, name, usage, &usage_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading Extended Key Usage: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (grub_strncmp (codeSigningUsage_oid, usage, usage_size) == 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "extended key usage missing Code Signing usage");
|
||||
|
||||
cleanup:
|
||||
asn1_delete_structure (&extendedasn);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
|
||||
*
|
||||
* Extension ::= SEQUENCE {
|
||||
* extnID OBJECT IDENTIFIER,
|
||||
* critical BOOLEAN DEFAULT FALSE,
|
||||
* extnValue OCTET STRING
|
||||
* -- contains the DER encoding of an ASN.1 value
|
||||
* -- corresponding to the extension type identified
|
||||
* -- by extnID
|
||||
* }
|
||||
*
|
||||
* A certificate must:
|
||||
* - contain the Digital Signature usage
|
||||
* - not be a CA
|
||||
* - contain no extended usages, or contain the Code Signing extended usage
|
||||
* - not contain any other critical extensions (RFC 5280 s 4.2)
|
||||
*/
|
||||
static grub_err_t
|
||||
verify_extensions (asn1_node cert)
|
||||
{
|
||||
grub_int32_t result;
|
||||
grub_int32_t ext, num_extensions = 0;
|
||||
grub_int32_t usage_present = 0, constraints_present = 0, extended_usage_present = 0;
|
||||
char *oid_path, *critical_path, *value_path;
|
||||
char extnID[GRUB_MAX_OID_LEN];
|
||||
grub_int32_t extnID_size;
|
||||
grub_err_t err;
|
||||
char critical[6]; /* We get either "TRUE" or "FALSE". */
|
||||
grub_int32_t critical_size;
|
||||
grub_uint8_t *value;
|
||||
grub_int32_t value_size;
|
||||
|
||||
result = asn1_number_of_elements (cert, "tbsCertificate.extensions", &num_extensions);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE, "error counting number of extensions: %s",
|
||||
asn1_strerror (result));
|
||||
|
||||
if (num_extensions < 2)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"insufficient number of extensions for certificate, need at least 2, got %d",
|
||||
num_extensions);
|
||||
|
||||
for (ext = 1; ext <= num_extensions; ext++)
|
||||
{
|
||||
oid_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnID", ext);
|
||||
if (oid_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error extension OID path is empty");
|
||||
return err;
|
||||
}
|
||||
|
||||
extnID_size = sizeof (extnID);
|
||||
result = asn1_read_value (cert, oid_path, extnID, &extnID_size);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading extension OID: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup_oid_path;
|
||||
}
|
||||
|
||||
critical_path = grub_xasprintf ("tbsCertificate.extensions.?%d.critical", ext);
|
||||
if (critical_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error critical path is empty");
|
||||
goto cleanup_oid_path;
|
||||
}
|
||||
|
||||
critical_size = sizeof (critical);
|
||||
result = asn1_read_value (cert, critical_path, critical, &critical_size);
|
||||
if (result == ASN1_ELEMENT_NOT_FOUND)
|
||||
critical[0] = '\0';
|
||||
else if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading extension criticality: %s",
|
||||
asn1_strerror (result));
|
||||
goto cleanup_critical_path;
|
||||
}
|
||||
|
||||
value_path = grub_xasprintf ("tbsCertificate.extensions.?%d.extnValue", ext);
|
||||
if (value_path == NULL)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "error extnValue path is empty");
|
||||
goto cleanup_critical_path;
|
||||
}
|
||||
|
||||
value = grub_asn1_allocate_and_read (cert, value_path,
|
||||
"certificate extension value", &value_size);
|
||||
if (value == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup_value_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we must see if we recognise the OID. If we have an unrecognised
|
||||
* critical extension we MUST bail.
|
||||
*/
|
||||
if (grub_strncmp (keyUsage_oid, extnID, extnID_size) == 0)
|
||||
{
|
||||
err = verify_key_usage (value, value_size);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup_value;
|
||||
|
||||
usage_present++;
|
||||
}
|
||||
else if (grub_strncmp (basicConstraints_oid, extnID, extnID_size) == 0)
|
||||
{
|
||||
err = verify_basic_constraints (value, value_size);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup_value;
|
||||
|
||||
constraints_present++;
|
||||
}
|
||||
else if (grub_strncmp (extendedKeyUsage_oid, extnID, extnID_size) == 0)
|
||||
{
|
||||
err = verify_extended_key_usage (value, value_size);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup_value;
|
||||
|
||||
extended_usage_present++;
|
||||
}
|
||||
else if (grub_strncmp ("TRUE", critical, critical_size) == 0)
|
||||
{
|
||||
/*
|
||||
* Per the RFC, we must not process a certificate with a critical
|
||||
* extension we do not understand.
|
||||
*/
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"unhandled critical x509 extension with OID %s", extnID);
|
||||
goto cleanup_value;
|
||||
}
|
||||
|
||||
grub_free (value);
|
||||
grub_free (value_path);
|
||||
grub_free (critical_path);
|
||||
grub_free (oid_path);
|
||||
}
|
||||
|
||||
if (usage_present != 1)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"unexpected number of Key Usage extensions - expected 1, got %d",
|
||||
usage_present);
|
||||
|
||||
if (constraints_present != 1)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"unexpected number of basic constraints extensions - expected 1, got %d",
|
||||
constraints_present);
|
||||
|
||||
if (extended_usage_present > 1)
|
||||
return grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"unexpected number of Extended Key Usage extensions - expected 0 or 1, got %d",
|
||||
extended_usage_present);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
cleanup_value:
|
||||
grub_free (value);
|
||||
cleanup_value_path:
|
||||
grub_free (value_path);
|
||||
cleanup_critical_path:
|
||||
grub_free (critical_path);
|
||||
cleanup_oid_path:
|
||||
grub_free (oid_path);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
add_cert_fingerprint (const void *data, const grub_size_t data_size,
|
||||
grub_x509_cert_t *const cert)
|
||||
{
|
||||
/* Add SHA256 hash of certificate. */
|
||||
grub_crypto_hash ((gcry_md_spec_t *) &_gcry_digest_spec_sha256,
|
||||
&cert->fingerprint[GRUB_FINGERPRINT_SHA256], data, data_size);
|
||||
/* Add SHA384 hash of certificate. */
|
||||
grub_crypto_hash ((gcry_md_spec_t *) &_gcry_digest_spec_sha384,
|
||||
&cert->fingerprint[GRUB_FINGERPRINT_SHA384], data, data_size);
|
||||
/* Add SHA512 hash of certificate. */
|
||||
grub_crypto_hash ((gcry_md_spec_t *) &_gcry_digest_spec_sha512,
|
||||
&cert->fingerprint[GRUB_FINGERPRINT_SHA512], data, data_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse a certificate whose DER-encoded form is in @data, of size @data_size.
|
||||
* Return the results in @results, which must point to an allocated x509
|
||||
* certificate.
|
||||
*/
|
||||
grub_err_t
|
||||
grub_x509_cert_parse (const void *data, grub_size_t data_size, grub_x509_cert_t *results)
|
||||
{
|
||||
grub_int32_t result = 0;
|
||||
asn1_node cert;
|
||||
grub_err_t err;
|
||||
grub_int32_t tmp_size;
|
||||
grub_int32_t size = (grub_int32_t) data_size;
|
||||
|
||||
if (data_size > GRUB_UINT_MAX)
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE,
|
||||
"cannot parse a certificate where data size > GRUB_UINT_MAX");
|
||||
|
||||
result = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.Certificate", &cert);
|
||||
if (result != ASN1_SUCCESS)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
"could not create ASN.1 structure for certificate: %s",
|
||||
asn1_strerror (result));
|
||||
|
||||
result = asn1_der_decoding2 (&cert, data, &size, ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
|
||||
if (result != ASN1_SUCCESS)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_BAD_FILE_TYPE,
|
||||
"could not parse DER for certificate: %s", asn1_error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* TBSCertificate ::= SEQUENCE {
|
||||
* version [0] EXPLICIT Version DEFAULT v1
|
||||
*/
|
||||
err = check_version (cert, results);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup;
|
||||
|
||||
/*
|
||||
* serialNumber CertificateSerialNumber,
|
||||
*
|
||||
* CertificateSerialNumber ::= INTEGER
|
||||
*/
|
||||
results->serial = grub_asn1_allocate_and_read (cert, "tbsCertificate.serialNumber",
|
||||
"certificate serial number", &tmp_size);
|
||||
if (results->serial == NULL)
|
||||
{
|
||||
err = grub_errno;
|
||||
goto cleanup;
|
||||
}
|
||||
/*
|
||||
* It's safe to cast the signed int to an unsigned here, we know
|
||||
* length is non-negative.
|
||||
*/
|
||||
results->serial_len = tmp_size;
|
||||
|
||||
/*
|
||||
* signature AlgorithmIdentifier,
|
||||
*
|
||||
* We don't load the signature or issuer at the moment,
|
||||
* as we don't attempt x509 verification.
|
||||
*/
|
||||
|
||||
/*
|
||||
* validity Validity,
|
||||
*
|
||||
* Validity ::= SEQUENCE {
|
||||
* notBefore Time,
|
||||
* notAfter Time }
|
||||
*
|
||||
* We can't validate this reasonably, we have no true time source on several
|
||||
* platforms. For now we do not parse them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* issuer Name,
|
||||
*
|
||||
* This is an X501 name, we parse out just the issuer.
|
||||
*/
|
||||
err = read_name (cert, "tbsCertificate.issuer", &results->issuer, &results->issuer_len);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup_serial;
|
||||
|
||||
/*
|
||||
* subject Name,
|
||||
*
|
||||
* This is an X501 name, we parse out just the CN.
|
||||
*/
|
||||
err = read_name (cert, "tbsCertificate.subject", &results->subject, &results->subject_len);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup_issuer;
|
||||
|
||||
/*
|
||||
* TBSCertificate ::= SEQUENCE {
|
||||
* ...
|
||||
* subjectPublicKeyInfo SubjectPublicKeyInfo,
|
||||
* ...
|
||||
*/
|
||||
err = grub_x509_read_subject_public_key (cert, results);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup_name;
|
||||
|
||||
/*
|
||||
* TBSCertificate ::= SEQUENCE {
|
||||
* ...
|
||||
* extensions [3] EXPLICIT Extensions OPTIONAL
|
||||
* -- If present, version MUST be v3
|
||||
* }
|
||||
*/
|
||||
err = verify_extensions (cert);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
goto cleanup_mpis;
|
||||
|
||||
/*
|
||||
* We do not read or check the signature on the certificate:
|
||||
* as discussed we do not try to validate the certificate but trust
|
||||
* it implictly.
|
||||
*/
|
||||
asn1_delete_structure (&cert);
|
||||
|
||||
/* Add the fingerprint of the certificate. */
|
||||
add_cert_fingerprint (data, data_size, results);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
cleanup_mpis:
|
||||
_gcry_mpi_release (results->mpis[GRUB_RSA_PK_MODULUS]);
|
||||
_gcry_mpi_release (results->mpis[GRUB_RSA_PK_EXPONENT]);
|
||||
cleanup_name:
|
||||
grub_free (results->subject);
|
||||
cleanup_issuer:
|
||||
grub_free (results->issuer);
|
||||
cleanup_serial:
|
||||
grub_free (results->serial);
|
||||
cleanup:
|
||||
asn1_delete_structure (&cert);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release all the storage associated with the x509 certificate. If the caller
|
||||
* dynamically allocated the certificate, it must free it. The caller is also
|
||||
* responsible for maintenance of the linked list.
|
||||
*/
|
||||
void
|
||||
grub_x509_cert_release (grub_x509_cert_t *cert)
|
||||
{
|
||||
grub_free (cert->issuer);
|
||||
grub_free (cert->subject);
|
||||
grub_free (cert->serial);
|
||||
_gcry_mpi_release (cert->mpis[GRUB_RSA_PK_MODULUS]);
|
||||
_gcry_mpi_release (cert->mpis[GRUB_RSA_PK_EXPONENT]);
|
||||
}
|
||||
@ -28,6 +28,7 @@
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/partition.h>
|
||||
#include <grub/tpm.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
@ -127,12 +128,34 @@ set_loader_device_part_uuid (void)
|
||||
return status;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
set_loader_active_pcr_banks (void)
|
||||
{
|
||||
grub_efi_uint32_t active_pcr_banks;
|
||||
char *active_pcr_banks_str;
|
||||
grub_err_t status;
|
||||
|
||||
active_pcr_banks = grub_tpm2_active_pcr_banks();
|
||||
active_pcr_banks_str = grub_xasprintf ("0x%08x", active_pcr_banks);
|
||||
if (active_pcr_banks_str == NULL)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate active PCR banks string"));
|
||||
|
||||
status = grub_efi_set_variable_to_string ("LoaderTpm2ActivePcrBanks",
|
||||
&bli_vendor_guid,
|
||||
active_pcr_banks_str,
|
||||
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
|
||||
grub_free (active_pcr_banks_str);
|
||||
return status;
|
||||
}
|
||||
|
||||
GRUB_MOD_INIT (bli)
|
||||
{
|
||||
grub_efi_set_variable_to_string ("LoaderInfo", &bli_vendor_guid, PACKAGE_STRING,
|
||||
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
|
||||
set_loader_device_part_uuid ();
|
||||
set_loader_active_pcr_banks ();
|
||||
/* No error here is critical, other than being logged */
|
||||
grub_print_error ();
|
||||
}
|
||||
|
||||
1503
grub-core/commands/blsuki.c
Normal file
1503
grub-core/commands/blsuki.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -129,6 +129,7 @@ grub_cmd_lsefi (grub_command_t cmd __attribute__ ((unused)),
|
||||
|
||||
}
|
||||
|
||||
grub_free (handles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -47,6 +47,7 @@ static const struct guid_mapping guid_mappings[] =
|
||||
{ GRUB_EFI_HOB_LIST_GUID, "HOB LIST"},
|
||||
{ GRUB_EFI_IMAGE_SECURITY_DATABASE_GUID, "IMAGE EXECUTION INFORMATION"},
|
||||
{ GRUB_EFI_LZMA_CUSTOM_DECOMPRESS_GUID, "LZMA CUSTOM DECOMPRESS"},
|
||||
{ GRUB_EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMORY ATTRIBUTES TABLE"},
|
||||
{ GRUB_EFI_MEMORY_TYPE_INFORMATION_GUID, "MEMORY TYPE INFO"},
|
||||
{ GRUB_EFI_MPS_TABLE_GUID, "MPS"},
|
||||
{ GRUB_EFI_RT_PROPERTIES_TABLE_GUID, "RT PROPERTIES"},
|
||||
@ -54,6 +55,7 @@ static const struct guid_mapping guid_mappings[] =
|
||||
{ GRUB_EFI_SMBIOS_TABLE_GUID, "SMBIOS"},
|
||||
{ GRUB_EFI_SMBIOS3_TABLE_GUID, "SMBIOS3"},
|
||||
{ GRUB_EFI_SYSTEM_RESOURCE_TABLE_GUID, "SYSTEM RESOURCE TABLE"},
|
||||
{ GRUB_EFI_TCG2_FINAL_EVENTS_TABLE_GUID, "TCG2 FINAL EVENTS TABLE"},
|
||||
{ GRUB_EFI_TIANO_CUSTOM_DECOMPRESS_GUID, "TIANO CUSTOM DECOMPRESS"},
|
||||
{ GRUB_EFI_TSC_FREQUENCY_GUID, "TSC FREQUENCY"},
|
||||
};
|
||||
|
||||
@ -39,6 +39,7 @@ static grub_uint8_t grub_tpm_version;
|
||||
|
||||
static grub_int8_t tpm1_present = -1;
|
||||
static grub_int8_t tpm2_present = -1;
|
||||
static grub_efi_int64_t tpm2_active_pcr_banks = -1;
|
||||
|
||||
static grub_efi_boolean_t
|
||||
grub_tpm1_present (grub_efi_tpm_protocol_t *tpm)
|
||||
@ -112,6 +113,7 @@ grub_tpm_handle_find (grub_efi_handle_t *tpm_handle,
|
||||
grub_tpm_version = 1;
|
||||
*protocol_version = 1;
|
||||
grub_dprintf ("tpm", "TPM handle Found, version: 1\n");
|
||||
grub_free (handles);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -124,6 +126,7 @@ grub_tpm_handle_find (grub_efi_handle_t *tpm_handle,
|
||||
grub_tpm_version = 2;
|
||||
*protocol_version = 2;
|
||||
grub_dprintf ("tpm", "TPM handle Found, version: 2\n");
|
||||
grub_free (handles);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -332,3 +335,49 @@ grub_tpm_present (void)
|
||||
return grub_tpm2_present (tpm);
|
||||
}
|
||||
}
|
||||
|
||||
grub_uint32_t
|
||||
grub_tpm2_active_pcr_banks (void)
|
||||
{
|
||||
EFI_TCG2_BOOT_SERVICE_CAPABILITY caps;
|
||||
grub_efi_handle_t tpm_handle;
|
||||
grub_efi_uint8_t protocol_version;
|
||||
grub_efi_tpm2_protocol_t *tpm;
|
||||
grub_efi_uint32_t active_pcr_banks;
|
||||
grub_efi_status_t status;
|
||||
|
||||
if (tpm2_active_pcr_banks >= 0)
|
||||
return (grub_uint32_t) tpm2_active_pcr_banks;
|
||||
|
||||
if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
|
||||
|
||||
if (protocol_version == 1)
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = 0); /* We report TPM2 status. */
|
||||
|
||||
tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
|
||||
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if (tpm == NULL)
|
||||
{
|
||||
grub_dprintf ("tpm", "Cannot open TPM2 protocol\n");
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
|
||||
}
|
||||
|
||||
if (!grub_tpm2_present (tpm))
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
|
||||
|
||||
caps.Size = (grub_uint8_t) sizeof (caps);
|
||||
status = tpm->get_capability (tpm, &caps);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = 0);
|
||||
if (caps.StructureVersion.Major < 1 ||
|
||||
(caps.StructureVersion.Major == 1 && caps.StructureVersion.Minor < 1))
|
||||
/* There's a working TPM2 but without querying protocol, let userspace figure it out. */
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = GRUB_UINT_MAX);
|
||||
|
||||
status = tpm->get_active_pcr_banks (tpm, &active_pcr_banks);
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = 0); /* Assume none available if the call fails. */
|
||||
|
||||
return (grub_uint32_t) (tpm2_active_pcr_banks = active_pcr_banks);
|
||||
}
|
||||
|
||||
@ -139,6 +139,9 @@ grub_register_extcmd_lockdown (const char *name, grub_extcmd_func_t func,
|
||||
void
|
||||
grub_unregister_extcmd (grub_extcmd_t ext)
|
||||
{
|
||||
if (ext == NULL)
|
||||
return;
|
||||
|
||||
grub_unregister_command (ext->cmd);
|
||||
grub_free (ext);
|
||||
}
|
||||
|
||||
@ -27,67 +27,20 @@
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
static int
|
||||
ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
|
||||
grub_uint32_t eventtype,
|
||||
const char *description,
|
||||
grub_size_t description_size,
|
||||
void *buf, grub_size_t size)
|
||||
{
|
||||
struct tpm_2hash_ext_log
|
||||
{
|
||||
struct grub_ieee1275_common_hdr common;
|
||||
grub_ieee1275_cell_t method;
|
||||
grub_ieee1275_cell_t ihandle;
|
||||
grub_ieee1275_cell_t size;
|
||||
grub_ieee1275_cell_t buf;
|
||||
grub_ieee1275_cell_t description_size;
|
||||
grub_ieee1275_cell_t description;
|
||||
grub_ieee1275_cell_t eventtype;
|
||||
grub_ieee1275_cell_t pcrindex;
|
||||
grub_ieee1275_cell_t catch_result;
|
||||
grub_ieee1275_cell_t rc;
|
||||
};
|
||||
struct tpm_2hash_ext_log args;
|
||||
|
||||
INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
|
||||
args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
|
||||
args.ihandle = grub_ieee1275_tpm_ihandle;
|
||||
args.pcrindex = pcrindex;
|
||||
args.eventtype = eventtype;
|
||||
args.description = (grub_ieee1275_cell_t) description;
|
||||
args.description_size = description_size;
|
||||
args.buf = (grub_ieee1275_cell_t) buf;
|
||||
args.size = (grub_ieee1275_cell_t) size;
|
||||
|
||||
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* catch_result is set if firmware does not support 2hash-ext-log
|
||||
* rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
|
||||
*/
|
||||
if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
tpm2_log_event (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
|
||||
const char *description)
|
||||
{
|
||||
static int error_displayed = 0;
|
||||
int rc;
|
||||
grub_err_t err;
|
||||
|
||||
rc = ibmvtpm_2hash_ext_log (pcr, EV_IPL,
|
||||
description, grub_strlen(description) + 1,
|
||||
buf, size);
|
||||
if (rc && !error_displayed)
|
||||
err = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, EV_IPL,
|
||||
description, grub_strlen(description) + 1,
|
||||
buf, size);
|
||||
if (err != GRUB_ERR_NONE && !error_displayed)
|
||||
{
|
||||
error_displayed++;
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE,
|
||||
"2HASH-EXT-LOG failed: Firmware is likely too old.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
@ -143,7 +143,7 @@ legacy_file (const char *filename)
|
||||
args[0] = oldname;
|
||||
grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
|
||||
NULL, NULL,
|
||||
entrysrc, 0);
|
||||
entrysrc, 0, NULL);
|
||||
grub_free (args);
|
||||
entrysrc[0] = 0;
|
||||
grub_free (oldname);
|
||||
@ -204,7 +204,7 @@ legacy_file (const char *filename)
|
||||
}
|
||||
args[0] = entryname;
|
||||
grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
|
||||
NULL, NULL, entrysrc, 0);
|
||||
NULL, NULL, entrysrc, 0, NULL);
|
||||
grub_free (args);
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,18 @@ grub_cmd_lsfreemem (grub_command_t cmd __attribute__ ((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_lsmemregions (grub_command_t cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
|
||||
{
|
||||
#ifndef GRUB_MACHINE_EMU
|
||||
grub_mm_dump_regions ();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_stress_big_allocs (grub_command_t cmd __attribute__ ((unused)),
|
||||
@ -132,7 +144,7 @@ grub_cmd_stress_big_allocs (grub_command_t cmd __attribute__ ((unused)),
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_command_t cmd_lsmem, cmd_lsfreemem, cmd_sba;
|
||||
static grub_command_t cmd_lsmem, cmd_lsfreemem, cmd_lsmemregions, cmd_sba;
|
||||
|
||||
GRUB_MOD_INIT (memtools)
|
||||
{
|
||||
@ -140,6 +152,8 @@ GRUB_MOD_INIT (memtools)
|
||||
0, N_("List free and allocated memory blocks."));
|
||||
cmd_lsfreemem = grub_register_command ("lsfreemem", grub_cmd_lsfreemem,
|
||||
0, N_("List free memory blocks."));
|
||||
cmd_lsmemregions = grub_register_command ("lsmemregions", grub_cmd_lsmemregions,
|
||||
0, N_("List memory regions."));
|
||||
cmd_sba = grub_register_command ("stress_big_allocs", grub_cmd_stress_big_allocs,
|
||||
0, N_("Stress test large allocations."));
|
||||
}
|
||||
@ -148,5 +162,6 @@ GRUB_MOD_FINI (memtools)
|
||||
{
|
||||
grub_unregister_command (cmd_lsmem);
|
||||
grub_unregister_command (cmd_lsfreemem);
|
||||
grub_unregister_command (cmd_lsmemregions);
|
||||
grub_unregister_command (cmd_sba);
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
|
||||
char **classes, const char *id,
|
||||
const char *users, const char *hotkey,
|
||||
const char *prefix, const char *sourcecode,
|
||||
int submenu)
|
||||
int submenu, grub_blsuki_entry_t *blsuki)
|
||||
{
|
||||
int menu_hotkey = 0;
|
||||
char **menu_args = NULL;
|
||||
@ -188,6 +188,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
|
||||
(*last)->args = menu_args;
|
||||
(*last)->sourcecode = menu_sourcecode;
|
||||
(*last)->submenu = submenu;
|
||||
(*last)->blsuki = blsuki;
|
||||
|
||||
menu->size++;
|
||||
return GRUB_ERR_NONE;
|
||||
@ -265,6 +266,9 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
if (! argc)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
|
||||
|
||||
if (! grub_strlen (args[argc - 1]))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "menuentry title is missing");
|
||||
|
||||
if (ctxt->state[3].set && ctxt->script)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
|
||||
|
||||
@ -286,7 +290,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
users,
|
||||
ctxt->state[2].arg, 0,
|
||||
ctxt->state[3].arg,
|
||||
ctxt->extcmd->cmd->name[0] == 's');
|
||||
ctxt->extcmd->cmd->name[0] == 's',
|
||||
NULL);
|
||||
|
||||
src = args[argc - 1];
|
||||
args[argc - 1] = NULL;
|
||||
@ -303,7 +308,7 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
ctxt->state[0].args, ctxt->state[4].arg,
|
||||
users,
|
||||
ctxt->state[2].arg, prefix, src + 1,
|
||||
ctxt->extcmd->cmd->name[0] == 's');
|
||||
ctxt->extcmd->cmd->name[0] == 's', NULL);
|
||||
|
||||
src[len - 1] = ch;
|
||||
args[argc - 1] = src;
|
||||
|
||||
@ -136,10 +136,6 @@ struct signature_v4_header
|
||||
grub_uint16_t hashed_sub;
|
||||
} GRUB_PACKED;
|
||||
|
||||
struct gcry_pk_spec *grub_crypto_pk_dsa;
|
||||
struct gcry_pk_spec *grub_crypto_pk_ecdsa;
|
||||
struct gcry_pk_spec *grub_crypto_pk_rsa;
|
||||
|
||||
struct
|
||||
{
|
||||
const char *name;
|
||||
@ -924,7 +920,7 @@ GRUB_MOD_INIT(pgp)
|
||||
grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
|
||||
|
||||
/* Not an ELF module, skip. */
|
||||
if (header->type != OBJ_TYPE_PUBKEY)
|
||||
if (header->type != OBJ_TYPE_GPG_PUBKEY)
|
||||
continue;
|
||||
|
||||
pseudo_file.fs = &pseudo_fs;
|
||||
|
||||
@ -403,7 +403,7 @@ test_parse (char **args, int *argn, int argc, int *depth)
|
||||
if (++(*depth) > MAX_TEST_RECURSION_DEPTH)
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded"));
|
||||
depth--;
|
||||
(*depth)--;
|
||||
return ctx.or || ctx.and;
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include <tss2_buffer.h>
|
||||
#include <tss2_types.h>
|
||||
#include <tss2_mu.h>
|
||||
#include <tcg2.h>
|
||||
|
||||
#include "tpm2_args.h"
|
||||
#include "tpm2.h"
|
||||
@ -47,6 +48,7 @@ typedef enum tpm2_protector_options
|
||||
OPTION_MODE,
|
||||
OPTION_PCRS,
|
||||
OPTION_BANK,
|
||||
OPTION_CAPPCRS,
|
||||
OPTION_TPM2KEY,
|
||||
OPTION_KEYFILE,
|
||||
OPTION_SRK,
|
||||
@ -61,6 +63,8 @@ typedef struct tpm2_protector_context
|
||||
grub_uint8_t pcr_count;
|
||||
grub_srk_type_t srk_type;
|
||||
TPM_ALG_ID_t bank;
|
||||
grub_uint8_t cap_pcrs[TPM_MAX_PCRS];
|
||||
grub_uint8_t cap_pcr_count;
|
||||
const char *tpm2key;
|
||||
const char *keyfile;
|
||||
TPM_HANDLE_t srk;
|
||||
@ -100,6 +104,16 @@ static const struct grub_arg_option tpm2_protector_init_cmd_options[] =
|
||||
N_("Bank of PCRs used to authorize key release: "
|
||||
"SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"),
|
||||
},
|
||||
{
|
||||
.longarg = "cap-pcrs",
|
||||
.shortarg = 'c',
|
||||
.flags = 0,
|
||||
.arg = NULL,
|
||||
.type = ARG_TYPE_STRING,
|
||||
.doc =
|
||||
N_("Comma-separated list of PCRs to be capped after key release "
|
||||
"e.g., '7,11'."),
|
||||
},
|
||||
/* SRK-mode options */
|
||||
{
|
||||
.longarg = "tpm2key",
|
||||
@ -1212,19 +1226,45 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
|
||||
return err;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
tpm2_protector_cap_pcrs (const tpm2_protector_context_t *ctx)
|
||||
{
|
||||
grub_uint8_t i;
|
||||
grub_err_t err;
|
||||
|
||||
for (i = 0; i < ctx->cap_pcr_count; i++)
|
||||
{
|
||||
err = grub_tcg2_cap_pcr (ctx->cap_pcrs[i]);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
return err;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
tpm2_protector_recover (const tpm2_protector_context_t *ctx,
|
||||
grub_uint8_t **key, grub_size_t *key_size)
|
||||
{
|
||||
grub_err_t err;
|
||||
|
||||
switch (ctx->mode)
|
||||
{
|
||||
case TPM2_PROTECTOR_MODE_SRK:
|
||||
return tpm2_protector_srk_recover (ctx, key, key_size);
|
||||
err = tpm2_protector_srk_recover (ctx, key, key_size);
|
||||
break;
|
||||
case TPM2_PROTECTOR_MODE_NV:
|
||||
return tpm2_protector_nv_recover (ctx, key, key_size);
|
||||
err = tpm2_protector_nv_recover (ctx, key, key_size);
|
||||
break;
|
||||
default:
|
||||
return GRUB_ERR_BAD_ARGUMENT;
|
||||
err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown Mode"));
|
||||
}
|
||||
|
||||
/* Cap the selected PCRs when the key is unsealed successfully */
|
||||
if (ctx->cap_pcr_count > 0 && err == GRUB_ERR_NONE)
|
||||
err = tpm2_protector_cap_pcrs (ctx);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
@ -1364,6 +1404,15 @@ tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (state[OPTION_CAPPCRS].set) /* cap-pcrs */
|
||||
{
|
||||
err = grub_tpm2_protector_parse_pcrs (state[OPTION_CAPPCRS].arg,
|
||||
tpm2_protector_ctx.cap_pcrs,
|
||||
&tpm2_protector_ctx.cap_pcr_count);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (state[OPTION_TPM2KEY].set) /* tpm2key */
|
||||
{
|
||||
err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
|
||||
@ -1465,6 +1514,7 @@ GRUB_MOD_INIT (tpm2_key_protector)
|
||||
N_("[-m mode] "
|
||||
"[-p pcr_list] "
|
||||
"[-b pcr_bank] "
|
||||
"[-c pcr_list] "
|
||||
"[-T tpm2_key_file_path] "
|
||||
"[-k sealed_key_file_path] "
|
||||
"[-s srk_handle] "
|
||||
|
||||
@ -90,7 +90,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
|
||||
0x06, (3 << 8) | index,
|
||||
langid, descstr.length, (char *) descstrp);
|
||||
|
||||
if (descstrp->length == 0)
|
||||
if (descstrp->length < 2)
|
||||
{
|
||||
grub_free (descstrp);
|
||||
*string = grub_strdup ("");
|
||||
@ -99,7 +99,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
|
||||
return GRUB_USB_ERR_NONE;
|
||||
}
|
||||
|
||||
*string = grub_malloc (descstr.length * 2 + 1);
|
||||
*string = grub_malloc (descstrp->length * 2 + 1);
|
||||
if (! *string)
|
||||
{
|
||||
grub_free (descstrp);
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include <grub/partition.h>
|
||||
#include <grub/key_protector.h>
|
||||
#include <grub/safemath.h>
|
||||
#include <grub/hwfeatures-gcry.h>
|
||||
|
||||
#ifdef GRUB_UTIL
|
||||
#include <grub/emu/hostdisk.h>
|
||||
@ -48,7 +49,8 @@ enum
|
||||
OPTION_KEYFILE_OFFSET,
|
||||
OPTION_KEYFILE_SIZE,
|
||||
OPTION_HEADER,
|
||||
OPTION_PROTECTOR
|
||||
OPTION_PROTECTOR,
|
||||
OPTION_HWACCEL
|
||||
};
|
||||
|
||||
static const struct grub_arg_option options[] =
|
||||
@ -64,6 +66,7 @@ static const struct grub_arg_option options[] =
|
||||
{"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING},
|
||||
{"protector", 'P', GRUB_ARG_OPTION_REPEATABLE,
|
||||
N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING},
|
||||
{"hw-accel", 'A', 0, N_("Enable hardware acceleration."), 0, 0},
|
||||
{0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
@ -1420,7 +1423,7 @@ grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs)
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
__grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
struct grub_cryptomount_args cargs = {0};
|
||||
@ -1629,6 +1632,23 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
|
||||
{
|
||||
struct grub_arg_list *state = ctxt->state;
|
||||
grub_err_t err;
|
||||
|
||||
if (state[OPTION_HWACCEL].set)
|
||||
grub_enable_gcry_hwf ();
|
||||
|
||||
err = __grub_cmd_cryptomount (ctxt, argc, args);
|
||||
|
||||
if (state[OPTION_HWACCEL].set)
|
||||
grub_reset_gcry_hwf ();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct grub_disk_dev grub_cryptodisk_dev = {
|
||||
.name = "cryptodisk",
|
||||
.id = GRUB_DISK_DEVICE_CRYPTODISK_ID,
|
||||
@ -1898,7 +1918,7 @@ GRUB_MOD_INIT (cryptodisk)
|
||||
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
|
||||
N_("[ [-p password] | [-k keyfile"
|
||||
" [-O keyoffset] [-S keysize] ] ] [-H file]"
|
||||
" [-P protector [-P protector ...]]"
|
||||
" [-P protector [-P protector ...]] | [-A]"
|
||||
" <SOURCE|-u UUID|-a|-b>"),
|
||||
N_("Mount a crypto device."), options);
|
||||
grub_procfs_register ("luks_script", &luks_script);
|
||||
|
||||
@ -464,9 +464,7 @@ geli_recover_key (grub_disk_t source, grub_cryptodisk_t dev, grub_cryptomount_ar
|
||||
grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt));
|
||||
grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len);
|
||||
|
||||
gcry_err = grub_crypto_hmac_fini (hnd, geomkey);
|
||||
if (gcry_err)
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
grub_crypto_hmac_fini (hnd, geomkey);
|
||||
}
|
||||
|
||||
gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,
|
||||
|
||||
@ -93,6 +93,7 @@ ofdisk_hash_add_real (char *devpath)
|
||||
grub_add (sz, sizeof ("ieee1275/"), &sz))
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of device path"));
|
||||
grub_free (p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -109,6 +110,8 @@ ofdisk_hash_add_real (char *devpath)
|
||||
if (grub_add (grub_strlen (p->devpath), 3, &sz))
|
||||
{
|
||||
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected while obtaining size of an open path"));
|
||||
grub_free (p->grub_devpath);
|
||||
grub_free (p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
|
||||
enum grub_luks2_kdf_type
|
||||
{
|
||||
LUKS2_KDF_TYPE_ARGON2I,
|
||||
LUKS2_KDF_TYPE_ARGON2ID,
|
||||
LUKS2_KDF_TYPE_PBKDF2
|
||||
};
|
||||
typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
|
||||
@ -159,13 +160,21 @@ luks2_parse_keyslot (grub_luks2_keyslot_t *out, const grub_json_t *keyslot)
|
||||
grub_json_getstring (&type, &kdf, "type") ||
|
||||
grub_json_getstring (&out->kdf.salt, &kdf, "salt"))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing or invalid KDF");
|
||||
else if (!grub_strcmp (type, "argon2i") || !grub_strcmp (type, "argon2id"))
|
||||
else if (!grub_strcmp (type, "argon2i"))
|
||||
{
|
||||
out->kdf.type = LUKS2_KDF_TYPE_ARGON2I;
|
||||
if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") ||
|
||||
grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") ||
|
||||
grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus"))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing Argon2i parameters");
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing Argon2i parameters");
|
||||
}
|
||||
else if (!grub_strcmp (type, "argon2id"))
|
||||
{
|
||||
out->kdf.type = LUKS2_KDF_TYPE_ARGON2ID;
|
||||
if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") ||
|
||||
grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") ||
|
||||
grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus"))
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing Argon2id parameters");
|
||||
}
|
||||
else if (!grub_strcmp (type, "pbkdf2"))
|
||||
{
|
||||
@ -444,6 +453,8 @@ luks2_decrypt_key (grub_uint8_t *out_key,
|
||||
grub_uint8_t salt[GRUB_CRYPTODISK_MAX_KEYLEN];
|
||||
grub_uint8_t *split_key = NULL;
|
||||
idx_t saltlen = sizeof (salt);
|
||||
int subalgo;
|
||||
unsigned long param[4];
|
||||
char cipher[32], *p;
|
||||
const gcry_md_spec_t *hash;
|
||||
gcry_err_code_t gcry_ret;
|
||||
@ -460,8 +471,29 @@ luks2_decrypt_key (grub_uint8_t *out_key,
|
||||
switch (k->kdf.type)
|
||||
{
|
||||
case LUKS2_KDF_TYPE_ARGON2I:
|
||||
ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
|
||||
goto err;
|
||||
case LUKS2_KDF_TYPE_ARGON2ID:
|
||||
if (k->kdf.type == LUKS2_KDF_TYPE_ARGON2I)
|
||||
subalgo = GRUB_GCRY_KDF_ARGON2I;
|
||||
else
|
||||
subalgo = GRUB_GCRY_KDF_ARGON2ID;
|
||||
|
||||
param[0] = k->area.key_size;
|
||||
param[1] = k->kdf.u.argon2i.time;
|
||||
param[2] = k->kdf.u.argon2i.memory;
|
||||
param[3] = k->kdf.u.argon2i.cpus;
|
||||
|
||||
gcry_ret = grub_crypto_argon2 (subalgo, param, 4,
|
||||
passphrase, passphraselen,
|
||||
salt, saltlen,
|
||||
NULL, 0, NULL, 0,
|
||||
k->area.key_size, area_key);
|
||||
if (gcry_ret)
|
||||
{
|
||||
ret = grub_crypto_gcry_error (gcry_ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
break;
|
||||
case LUKS2_KDF_TYPE_PBKDF2:
|
||||
hash = grub_crypto_lookup_md_by_name (k->kdf.u.pbkdf2.hash);
|
||||
if (!hash)
|
||||
|
||||
@ -203,6 +203,9 @@ grub_efiemu_count_symbols (const Elf_Ehdr *e)
|
||||
grub_efiemu_elfsyms = (struct grub_efiemu_elf_sym *)
|
||||
grub_calloc (grub_efiemu_nelfsyms, sizeof (struct grub_efiemu_elf_sym));
|
||||
|
||||
if (grub_efiemu_elfsyms == NULL)
|
||||
return grub_errno;
|
||||
|
||||
/* Relocators */
|
||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
|
||||
@ -2334,14 +2334,20 @@ struct embed_region {
|
||||
};
|
||||
|
||||
/*
|
||||
* https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs(5)#BOOTLOADER_SUPPORT
|
||||
* https://btrfs.readthedocs.io/en/latest/btrfs-man5.html#man-btrfs5-bootloader-support
|
||||
* or invoke "man 5 btrfs" and visit the "BOOTLOADER SUPPORT" subsection.
|
||||
* The first 1 MiB on each device is unused with the exception of primary
|
||||
* superblock that is on the offset 64 KiB and spans 4 KiB.
|
||||
*
|
||||
* Note: If this table is modified, also update
|
||||
* util/grub-editenv.c::fs_envblk_spec, which describes the file-system
|
||||
* specific layout of reserved raw blocks used as environment blocks so that
|
||||
* both stay consistent.
|
||||
*/
|
||||
|
||||
static const struct {
|
||||
struct embed_region available;
|
||||
struct embed_region used[6];
|
||||
struct embed_region used[9];
|
||||
} btrfs_head = {
|
||||
.available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */
|
||||
.used = {
|
||||
@ -2349,6 +2355,9 @@ static const struct {
|
||||
{GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */
|
||||
{GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */
|
||||
{GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */
|
||||
{(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS) - 1, 1}, /* Overflow guard. */
|
||||
{(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS), 1}, /* Environment Block. */
|
||||
{(GRUB_ENV_BTRFS_OFFSET >> GRUB_DISK_SECTOR_BITS) + 1, 1}, /* Overflow guard. */
|
||||
{GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */
|
||||
{0, 0} /* Array terminator. */
|
||||
}
|
||||
|
||||
@ -736,7 +736,9 @@ list_nodes (void *record, void *hook_arg)
|
||||
int mode = (grub_be_to_cpu16 (fileinfo->mode)
|
||||
& GRUB_HFSPLUS_FILEMODE_MASK);
|
||||
|
||||
if (mode == GRUB_HFSPLUS_FILEMODE_REG)
|
||||
if (mode == 0) /* Created by pre-Mac OS X. */
|
||||
type = GRUB_FSHELP_REG;
|
||||
else if (mode == GRUB_HFSPLUS_FILEMODE_REG)
|
||||
type = GRUB_FSHELP_REG;
|
||||
else if (mode == GRUB_HFSPLUS_FILEMODE_SYMLINK)
|
||||
type = GRUB_FSHELP_SYMLINK;
|
||||
|
||||
@ -233,7 +233,12 @@ next_attribute (grub_uint8_t *curr_attribute, void *end, bool validate)
|
||||
return NULL;
|
||||
|
||||
next += u16at (curr_attribute, 4);
|
||||
if (validate && validate_attribute (next, end) == false)
|
||||
if (validate)
|
||||
{
|
||||
if (validate_attribute (next, end) == false)
|
||||
return NULL;
|
||||
}
|
||||
else if (next >= (grub_uint8_t *) end)
|
||||
return NULL;
|
||||
|
||||
return next;
|
||||
|
||||
@ -2743,7 +2743,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
|
||||
grub_uint64_t blkid, blksz; /* the block id this object dnode is in */
|
||||
int epbs; /* shift of number of dnodes in a block */
|
||||
int idx; /* index within a block */
|
||||
void *dnbuf;
|
||||
dnode_phys_t *dnbuf;
|
||||
grub_err_t err;
|
||||
grub_zfs_endian_t endian;
|
||||
|
||||
@ -2773,7 +2773,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
|
||||
|
||||
grub_dprintf ("zfs", "endian = %d, blkid=%llx\n", mdn->endian,
|
||||
(unsigned long long) blkid);
|
||||
err = dmu_read (mdn, blkid, &dnbuf, &endian, data);
|
||||
err = dmu_read (mdn, blkid, (void **) &dnbuf, &endian, data);
|
||||
if (err)
|
||||
return err;
|
||||
grub_dprintf ("zfs", "alive\n");
|
||||
@ -2795,7 +2795,7 @@ dnode_get (dnode_end_t * mdn, grub_uint64_t objnum, grub_uint8_t type,
|
||||
data->dnode_endian = endian;
|
||||
}
|
||||
|
||||
grub_memmove (&(buf->dn), (dnode_phys_t *) dnbuf + idx, DNODE_SIZE);
|
||||
grub_memmove (&(buf->dn), dnbuf + idx, DNODE_SIZE);
|
||||
if (data->dnode_buf == 0)
|
||||
/* dnbuf not used anymore if data->dnode_mdn malloc failed */
|
||||
grub_free (dnbuf);
|
||||
|
||||
@ -502,6 +502,8 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)),
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_command_t cmd;
|
||||
|
||||
GRUB_MOD_INIT (gettext)
|
||||
{
|
||||
const char *lang;
|
||||
@ -521,13 +523,14 @@ GRUB_MOD_INIT (gettext)
|
||||
grub_register_variable_hook ("locale_dir", NULL, read_main);
|
||||
grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary);
|
||||
|
||||
grub_register_command_p1 ("gettext", grub_cmd_translate,
|
||||
N_("STRING"),
|
||||
/* TRANSLATORS: It refers to passing the string through gettext.
|
||||
So it's "translate" in the same meaning as in what you're
|
||||
doing now.
|
||||
*/
|
||||
N_("Translates the string with the current settings."));
|
||||
cmd = grub_register_command_p1 ("gettext", grub_cmd_translate,
|
||||
N_("STRING"),
|
||||
/*
|
||||
* TRANSLATORS: It refers to passing the string through gettext.
|
||||
* So it's "translate" in the same meaning as in what you're
|
||||
* doing now.
|
||||
*/
|
||||
N_("Translates the string with the current settings."));
|
||||
|
||||
/* Reload .mo file information if lang changes. */
|
||||
grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang);
|
||||
@ -544,6 +547,8 @@ GRUB_MOD_FINI (gettext)
|
||||
grub_register_variable_hook ("secondary_locale_dir", NULL, NULL);
|
||||
grub_register_variable_hook ("lang", NULL, NULL);
|
||||
|
||||
grub_unregister_command (cmd);
|
||||
|
||||
grub_gettext_delete_list (&main_context);
|
||||
grub_gettext_delete_list (&secondary_context);
|
||||
|
||||
|
||||
251
grub-core/io/zstdio.c
Normal file
251
grub-core/io/zstdio.c
Normal file
@ -0,0 +1,251 @@
|
||||
/* zstdio.c - decompression support for zstd */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/fs.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#include "zstd.h"
|
||||
|
||||
#define STREAM_HEADER_SIZE 16
|
||||
|
||||
struct zstdio
|
||||
{
|
||||
grub_file_t file;
|
||||
ZSTD_DCtx *dctx;
|
||||
grub_size_t insize;
|
||||
grub_size_t outsize;
|
||||
|
||||
ZSTD_outBuffer output;
|
||||
ZSTD_inBuffer input;
|
||||
|
||||
grub_off_t saved_offset;
|
||||
grub_uint8_t bufs[];
|
||||
};
|
||||
typedef struct zstdio *zstdio_t;
|
||||
|
||||
static struct grub_fs zstdio_fs;
|
||||
|
||||
static bool
|
||||
test_header (grub_file_t file)
|
||||
{
|
||||
zstdio_t zstdio = file->data;
|
||||
size_t zret;
|
||||
|
||||
zstdio->input.pos = 0;
|
||||
zstdio->output.pos = 0;
|
||||
zstdio->output.size = zstdio->outsize;
|
||||
zstdio->input.size = grub_file_read (zstdio->file, zstdio->bufs,
|
||||
STREAM_HEADER_SIZE);
|
||||
if (zstdio->input.size != STREAM_HEADER_SIZE)
|
||||
return false;
|
||||
|
||||
zret = ZSTD_decompressStream (zstdio->dctx, &zstdio->output, &zstdio->input);
|
||||
if (ZSTD_isError (zret))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static grub_file_t
|
||||
grub_zstdio_open (grub_file_t io, enum grub_file_type type)
|
||||
{
|
||||
grub_file_t file;
|
||||
zstdio_t zstdio;
|
||||
|
||||
if (type & GRUB_FILE_TYPE_NO_DECOMPRESS)
|
||||
return io;
|
||||
|
||||
file = (grub_file_t) grub_zalloc (sizeof (*file));
|
||||
if (file == NULL)
|
||||
return NULL;
|
||||
|
||||
zstdio = grub_zalloc (sizeof (zstdio_t) + ZSTD_DStreamInSize () +
|
||||
ZSTD_DStreamOutSize ());
|
||||
if (zstdio == NULL)
|
||||
{
|
||||
grub_free (file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zstdio->file = io;
|
||||
zstdio->insize = ZSTD_DStreamInSize ();
|
||||
zstdio->outsize = ZSTD_DStreamOutSize ();
|
||||
zstdio->input.src = zstdio->bufs;
|
||||
zstdio->output.dst = &zstdio->bufs[zstdio->insize];
|
||||
|
||||
file->device = io->device;
|
||||
file->data = zstdio;
|
||||
file->fs = &zstdio_fs;
|
||||
file->size = GRUB_FILE_SIZE_UNKNOWN;
|
||||
file->not_easily_seekable = 1;
|
||||
|
||||
if (grub_file_tell (zstdio->file) != 0)
|
||||
if (grub_file_seek (zstdio->file, 0) == (grub_off_t) -1)
|
||||
{
|
||||
grub_free (file);
|
||||
grub_free (zstdio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zstdio->dctx = ZSTD_createDCtx ();
|
||||
if (zstdio->dctx == NULL)
|
||||
{
|
||||
grub_free (file);
|
||||
grub_free (zstdio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (test_header (file) == false)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
if (grub_file_seek (io, 0) == (grub_off_t) -1)
|
||||
{
|
||||
grub_free (file);
|
||||
grub_free (zstdio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZSTD_freeDCtx (zstdio->dctx);
|
||||
grub_free (zstdio);
|
||||
grub_free (file);
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_zstdio_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
zstdio_t zstdio = file->data;
|
||||
grub_ssize_t ret = 0;
|
||||
grub_ssize_t readret;
|
||||
grub_off_t current_offset;
|
||||
grub_off_t new_offset;
|
||||
grub_size_t delta;
|
||||
grub_size_t zret;
|
||||
|
||||
/* If seek backward need to reset decoder and start from beginning of file. */
|
||||
if (file->offset < zstdio->saved_offset)
|
||||
{
|
||||
ZSTD_initDStream (zstdio->dctx);
|
||||
zstdio->input.pos = 0;
|
||||
zstdio->input.size = 0;
|
||||
zstdio->output.pos = 0;
|
||||
zstdio->saved_offset = 0;
|
||||
grub_file_seek (zstdio->file, 0);
|
||||
}
|
||||
|
||||
current_offset = zstdio->saved_offset;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
zstdio->output.size = file->offset + ret + len - current_offset;
|
||||
if (zstdio->output.size > zstdio->outsize)
|
||||
zstdio->output.size = zstdio->outsize;
|
||||
if (zstdio->input.pos == zstdio->input.size)
|
||||
{
|
||||
readret = grub_file_read (zstdio->file, zstdio->bufs,
|
||||
zstdio->insize);
|
||||
if (readret < 0)
|
||||
return -1;
|
||||
|
||||
zstdio->input.size = readret;
|
||||
zstdio->input.pos = 0;
|
||||
}
|
||||
|
||||
zret = ZSTD_decompressStream (zstdio->dctx, &zstdio->output,
|
||||
&zstdio->input);
|
||||
if (ZSTD_isError (zret))
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_COMPRESSED_DATA,
|
||||
N_("zstd file corrupted or unsupported block options"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
new_offset = current_offset + zstdio->output.pos;
|
||||
|
||||
/* Store first chunk of data in buffer. */
|
||||
if (file->offset <= new_offset)
|
||||
{
|
||||
delta = new_offset - (file->offset + ret);
|
||||
grub_memmove (buf, (grub_uint8_t *) zstdio->output.dst +
|
||||
(zstdio->output.pos - delta),
|
||||
delta);
|
||||
len -= delta;
|
||||
buf += delta;
|
||||
ret += delta;
|
||||
}
|
||||
current_offset = new_offset;
|
||||
|
||||
zstdio->output.pos = 0;
|
||||
|
||||
if (zstdio->input.pos == 0 && zstdio->output.pos == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret >= 0)
|
||||
zstdio->saved_offset = file->offset + ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Release everything, including the underlying file object. */
|
||||
static grub_err_t
|
||||
grub_zstdio_close (grub_file_t file)
|
||||
{
|
||||
zstdio_t zstdio = file->data;
|
||||
|
||||
ZSTD_freeDCtx (zstdio->dctx);
|
||||
|
||||
grub_file_close (zstdio->file);
|
||||
grub_free (zstdio);
|
||||
|
||||
/* Device must not be closed twice. */
|
||||
file->device = 0;
|
||||
file->name = 0;
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
static struct grub_fs zstdio_fs = {
|
||||
.name = "zstdio",
|
||||
.fs_dir = 0,
|
||||
.fs_open = 0,
|
||||
.fs_read = grub_zstdio_read,
|
||||
.fs_close = grub_zstdio_close,
|
||||
.fs_label = 0,
|
||||
.next = 0
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT (zstdio)
|
||||
{
|
||||
grub_file_filter_register (GRUB_FILE_FILTER_ZSTDIO, grub_zstdio_open);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (zstdio)
|
||||
{
|
||||
grub_file_filter_unregister (GRUB_FILE_FILTER_ZSTDIO);
|
||||
}
|
||||
@ -104,6 +104,9 @@ grub_register_command_lockdown (const char *name,
|
||||
void
|
||||
grub_unregister_command (grub_command_t cmd)
|
||||
{
|
||||
if (cmd == NULL)
|
||||
return;
|
||||
|
||||
if ((cmd->prio & GRUB_COMMAND_FLAG_ACTIVE) && (cmd->next))
|
||||
cmd->next->prio |= GRUB_COMMAND_FLAG_ACTIVE;
|
||||
grub_list_remove (GRUB_AS_LIST (cmd));
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
void * GRUB_BUILTIN_ATTR
|
||||
memcpy (void *dest, const void *src, grub_size_t n)
|
||||
{
|
||||
return grub_memmove (dest, src, n);
|
||||
return grub_memcpy (dest, src, n);
|
||||
}
|
||||
void * GRUB_BUILTIN_ATTR
|
||||
memmove (void *dest, const void *src, grub_size_t n)
|
||||
@ -372,11 +372,11 @@ grub_int32_t
|
||||
__aeabi_idiv (grub_int32_t a, grub_int32_t b)
|
||||
__attribute__ ((alias ("__divsi3")));
|
||||
void *__aeabi_memcpy (void *dest, const void *src, grub_size_t n)
|
||||
__attribute__ ((alias ("grub_memcpy")));
|
||||
__attribute__ ((alias ("memcpy")));
|
||||
void *__aeabi_memcpy4 (void *dest, const void *src, grub_size_t n)
|
||||
__attribute__ ((alias ("grub_memcpy")));
|
||||
__attribute__ ((alias ("memcpy")));
|
||||
void *__aeabi_memcpy8 (void *dest, const void *src, grub_size_t n)
|
||||
__attribute__ ((alias ("grub_memcpy")));
|
||||
__attribute__ ((alias ("memcpy")));
|
||||
void *__aeabi_memset (void *s, int c, grub_size_t n)
|
||||
__attribute__ ((alias ("memset")));
|
||||
|
||||
|
||||
@ -152,6 +152,8 @@ shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
|
||||
case GRUB_FILE_TYPE_TESTLOAD:
|
||||
case GRUB_FILE_TYPE_GET_SIZE:
|
||||
case GRUB_FILE_TYPE_ZFS_ENCRYPTION_KEY:
|
||||
case GRUB_FILE_TYPE_CRYPTODISK_ENCRYPTION_KEY:
|
||||
case GRUB_FILE_TYPE_CRYPTODISK_DETACHED_HEADER:
|
||||
case GRUB_FILE_TYPE_CAT:
|
||||
case GRUB_FILE_TYPE_HEXCAT:
|
||||
case GRUB_FILE_TYPE_CMP:
|
||||
|
||||
@ -33,15 +33,24 @@ static struct grub_error_saved grub_error_stack_items[GRUB_ERROR_STACK_SIZE];
|
||||
static int grub_error_stack_pos;
|
||||
static int grub_error_stack_assert;
|
||||
|
||||
#ifdef grub_error
|
||||
#undef grub_error
|
||||
#endif
|
||||
|
||||
grub_err_t
|
||||
grub_error (grub_err_t n, const char *fmt, ...)
|
||||
grub_error (grub_err_t n, const char *file, const char *function, const int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int m;
|
||||
|
||||
grub_errno = n;
|
||||
|
||||
m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%s:%d:", file, function, line);
|
||||
if (m < 0)
|
||||
m = 0;
|
||||
|
||||
va_start (ap, fmt);
|
||||
grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap);
|
||||
grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap);
|
||||
va_end (ap);
|
||||
|
||||
return n;
|
||||
|
||||
@ -201,12 +201,12 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
|
||||
grub_err_t
|
||||
grub_file_close (grub_file_t file)
|
||||
{
|
||||
if (file->fs->mod)
|
||||
grub_dl_unref (file->fs->mod);
|
||||
|
||||
if (file->fs->fs_close)
|
||||
(file->fs->fs_close) (file);
|
||||
|
||||
if (file->fs->mod)
|
||||
grub_dl_unref (file->fs->mod);
|
||||
|
||||
if (file->device)
|
||||
grub_device_close (file->device);
|
||||
grub_free (file->name);
|
||||
|
||||
@ -352,6 +352,10 @@ grub_xen_setup_pvh (void)
|
||||
grub_xen_mm_init_regions ();
|
||||
|
||||
grub_rsdp_addr = pvh_start_info->rsdp_paddr;
|
||||
|
||||
grub_strncpy ((char *) grub_xen_start_page_addr->cmd_line,
|
||||
(const char *)(grub_addr_t) pvh_start_info->cmdline_paddr,
|
||||
GRUB_XEN_MAX_GUEST_CMDLINE);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
|
||||
@ -23,7 +23,6 @@
|
||||
|
||||
#define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_cell_t) -1)
|
||||
#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0)
|
||||
#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) -1)
|
||||
|
||||
|
||||
|
||||
|
||||
@ -49,6 +49,16 @@
|
||||
#if defined(__powerpc__) || defined(__i386__)
|
||||
#include <grub/ieee1275/alloc.h>
|
||||
#endif
|
||||
#if defined(__powerpc__)
|
||||
#include <grub/lockdown.h>
|
||||
#include <grub/powerpc/ieee1275/ieee1275.h>
|
||||
#include <grub/powerpc/ieee1275/platform_keystore.h>
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
#define GRUB_SB_DISABLED ((grub_uint32_t) 0)
|
||||
#define GRUB_SB_ENFORCE ((grub_uint32_t) 2)
|
||||
#endif
|
||||
|
||||
/* The maximum heap size we're going to claim at boot. Not used by sparc. */
|
||||
#ifdef __i386__
|
||||
@ -152,6 +162,8 @@ grub_machine_get_bootlocation (char **device, char **path)
|
||||
char *bootpath;
|
||||
char *filename;
|
||||
char *type;
|
||||
char *ret_device = NULL;
|
||||
char *ret_path = NULL;
|
||||
|
||||
bootpath = grub_ieee1275_get_boot_dev ();
|
||||
if (! bootpath)
|
||||
@ -167,7 +179,7 @@ grub_machine_get_bootlocation (char **device, char **path)
|
||||
dev = grub_ieee1275_get_aliasdevname (bootpath);
|
||||
canon = grub_ieee1275_canonicalise_devname (dev);
|
||||
if (! canon)
|
||||
return;
|
||||
goto done;
|
||||
ptr = canon + grub_strlen (canon) - 1;
|
||||
while (ptr > canon && (*ptr == ',' || *ptr == ':'))
|
||||
ptr--;
|
||||
@ -175,13 +187,17 @@ grub_machine_get_bootlocation (char **device, char **path)
|
||||
*ptr = 0;
|
||||
|
||||
if (grub_ieee1275_net_config)
|
||||
grub_ieee1275_net_config (canon, device, path, bootpath);
|
||||
grub_ieee1275_net_config (canon, &ret_device, &ret_path, bootpath);
|
||||
grub_free (dev);
|
||||
grub_free (canon);
|
||||
|
||||
/* Use path from net config if it is provided by cached DHCP info */
|
||||
if (ret_path != NULL)
|
||||
goto done;
|
||||
/* Fall through to use firmware bootpath */
|
||||
}
|
||||
else
|
||||
*device = grub_ieee1275_encode_devname (bootpath);
|
||||
grub_free (type);
|
||||
ret_device = grub_ieee1275_encode_devname (bootpath);
|
||||
|
||||
filename = grub_ieee1275_get_filename (bootpath);
|
||||
if (filename)
|
||||
@ -194,10 +210,18 @@ grub_machine_get_bootlocation (char **device, char **path)
|
||||
*lastslash = '\0';
|
||||
grub_translate_ieee1275_path (filename);
|
||||
|
||||
*path = filename;
|
||||
ret_path = filename;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
grub_free (type);
|
||||
grub_free (bootpath);
|
||||
|
||||
if (device != NULL)
|
||||
*device = ret_device;
|
||||
if (path != NULL)
|
||||
*path = ret_path;
|
||||
}
|
||||
|
||||
/* Claim some available memory in the first /memory node. */
|
||||
@ -994,7 +1018,51 @@ grub_parse_cmdline (void)
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef __powerpc__
|
||||
static void
|
||||
grub_ieee1275_get_secure_boot (void)
|
||||
{
|
||||
grub_ieee1275_phandle_t root;
|
||||
grub_uint32_t sb_mode = GRUB_SB_DISABLED;
|
||||
grub_int32_t rc;
|
||||
|
||||
rc = grub_ieee1275_finddevice ("/", &root);
|
||||
if (rc != 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node");
|
||||
return;
|
||||
}
|
||||
|
||||
rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &sb_mode, sizeof (sb_mode), 0);
|
||||
if (rc != 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /ibm,secure-boot property");
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Secure Boot Mode:
|
||||
* 0 - disabled
|
||||
* No signature verification is performed. This is the default.
|
||||
* 1 - audit
|
||||
* Signature verification is performed and if signature verification
|
||||
* fails, display the errors and allow the boot to continue.
|
||||
* 2 - enforce
|
||||
* Lockdown the GRUB. Signature verification is performed and If
|
||||
* signature verification fails, display the errors and stop the boot.
|
||||
*
|
||||
* Now, only support disabled and enforce.
|
||||
*/
|
||||
if (sb_mode == GRUB_SB_ENFORCE)
|
||||
{
|
||||
grub_dprintf ("ieee1275", "Secure Boot Enabled\n");
|
||||
grub_lockdown ();
|
||||
}
|
||||
else
|
||||
grub_dprintf ("ieee1275", "Secure Boot Disabled\n");
|
||||
|
||||
grub_pks_keystore_init ();
|
||||
}
|
||||
#endif /* __powerpc__ */
|
||||
grub_addr_t grub_modbase;
|
||||
|
||||
void
|
||||
@ -1020,6 +1088,10 @@ grub_machine_init (void)
|
||||
#else
|
||||
grub_install_get_time_ms (grub_rtc_get_time_ms);
|
||||
#endif
|
||||
|
||||
#ifdef __powerpc__
|
||||
grub_ieee1275_get_secure_boot ();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -201,6 +201,11 @@ grub_ieee1275_devalias_next (struct grub_ieee1275_devalias *alias)
|
||||
alias->path = 0;
|
||||
}
|
||||
tmp = grub_strdup (alias->name);
|
||||
if (tmp == NULL)
|
||||
{
|
||||
grub_ieee1275_devalias_free (alias);
|
||||
return 0;
|
||||
}
|
||||
if (grub_ieee1275_next_property (alias->parent_dev, tmp,
|
||||
alias->name) <= 0)
|
||||
{
|
||||
@ -432,9 +437,15 @@ grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
|
||||
ret = grub_strdup (args);
|
||||
else
|
||||
ret = grub_strndup (args, (grub_size_t)(comma - args));
|
||||
/* Consistently provide numbered partitions to GRUB.
|
||||
OpenBOOT traditionally uses alphabetical partition
|
||||
specifiers. */
|
||||
|
||||
if (ret == NULL)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Consistently provide numbered partitions to GRUB.
|
||||
* OpenBOOT traditionally uses alphabetical partition
|
||||
* specifiers.
|
||||
*/
|
||||
if (ret[0] >= 'a' && ret[0] <= 'z')
|
||||
ret[0] = '1' + (ret[0] - 'a');
|
||||
grub_free (args);
|
||||
@ -501,7 +512,20 @@ grub_ieee1275_encode_devname (const char *path)
|
||||
}
|
||||
if (partition && partition[0])
|
||||
{
|
||||
unsigned int partno = grub_strtoul (partition, 0, 0);
|
||||
unsigned long partno;
|
||||
const char *endptr;
|
||||
|
||||
partno = grub_strtoul (partition, &endptr, 0);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
if (*endptr != '\0' || partno > 65535 ||
|
||||
(partno == 0 && ! grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS)))
|
||||
{
|
||||
grub_free (partition);
|
||||
grub_free (device);
|
||||
grub_free (encoding);
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("invalid partition number"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*optr++ = ',';
|
||||
|
||||
@ -509,7 +533,7 @@ grub_ieee1275_encode_devname (const char *path)
|
||||
/* GRUB partition 1 is OF partition 0. */
|
||||
partno++;
|
||||
|
||||
grub_snprintf (optr, sizeof ("XXXXXXXXXXXX"), "%d", partno);
|
||||
grub_snprintf (optr, sizeof ("XXXXXXXXXXXX"), "%lu", partno);
|
||||
}
|
||||
else
|
||||
*optr = '\0';
|
||||
|
||||
@ -403,6 +403,9 @@ grub_machine_get_bootlocation (char **device, char **path)
|
||||
if (!syspart)
|
||||
return;
|
||||
loaddev = grub_strdup (syspart);
|
||||
if (loaddev == NULL)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
partptr = get_part (loaddev);
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/charset.h>
|
||||
#include <stddef.h>
|
||||
|
||||
union printf_arg
|
||||
{
|
||||
@ -99,6 +100,37 @@ grub_memmove (void *dest, const void *src, grub_size_t n)
|
||||
return dest;
|
||||
}
|
||||
|
||||
static void *
|
||||
__memcpy_aligned (void *dest, const void *src, grub_size_t n)
|
||||
{
|
||||
grub_addr_t *dw = (grub_addr_t *) dest;
|
||||
const grub_addr_t *sw = (const grub_addr_t *) src;
|
||||
grub_uint8_t *d;
|
||||
const grub_uint8_t *s;
|
||||
|
||||
for (; n >= sizeof (grub_addr_t); n -= sizeof (grub_addr_t))
|
||||
*dw++ = *sw++;
|
||||
|
||||
d = (grub_uint8_t *) dw;
|
||||
s = (const grub_uint8_t *) sw;
|
||||
for (; n > 0; n--)
|
||||
*d++ = *s++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *
|
||||
grub_memcpy (void *dest, const void *src, grub_size_t n)
|
||||
{
|
||||
/* Check if dest and src are aligned and n >= sizeof(grub_addr_t). */
|
||||
if (((grub_addr_t) dest & (sizeof (grub_addr_t) - 1)) == 0 &&
|
||||
((grub_addr_t) src & (sizeof (grub_addr_t) - 1)) == 0 &&
|
||||
n >= sizeof (grub_addr_t))
|
||||
return __memcpy_aligned (dest, src, n);
|
||||
|
||||
return grub_memmove (dest, src, n);
|
||||
}
|
||||
|
||||
char *
|
||||
grub_strcpy (char *dest, const char *src)
|
||||
{
|
||||
@ -231,14 +263,14 @@ grub_debug_enabled (const char * condition)
|
||||
}
|
||||
|
||||
void
|
||||
grub_real_dprintf (const char *file, const int line, const char *condition,
|
||||
grub_real_dprintf (const char *file, const char *function, const int line, const char *condition,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (grub_debug_enabled (condition))
|
||||
{
|
||||
grub_printf ("%s:%d:%s: ", file, line, condition);
|
||||
grub_printf ("%s:%s:%d:%s: ", file, function, line, condition);
|
||||
va_start (args, fmt);
|
||||
grub_vprintf (fmt, args);
|
||||
va_end (args);
|
||||
@ -401,6 +433,68 @@ grub_strword (const char *haystack, const char *needle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_strtok_r (char *s, const char *delim, char **save_ptr)
|
||||
{
|
||||
char *token;
|
||||
const char *c;
|
||||
bool is_delim;
|
||||
|
||||
if (s == NULL)
|
||||
s = *save_ptr;
|
||||
|
||||
/* Scan leading delimiters. */
|
||||
while (*s != '\0')
|
||||
{
|
||||
is_delim = false;
|
||||
for (c = delim; *c != '\0'; c++)
|
||||
{
|
||||
if (*s == *c)
|
||||
{
|
||||
is_delim = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_delim == true)
|
||||
s++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (*s == '\0')
|
||||
{
|
||||
*save_ptr = s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the end of the token. */
|
||||
token = s;
|
||||
while (*s != '\0')
|
||||
{
|
||||
for (c = delim; *c != '\0'; c++)
|
||||
{
|
||||
if (*s == *c)
|
||||
{
|
||||
*s = '\0';
|
||||
*save_ptr = s + 1;
|
||||
return token;
|
||||
}
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
*save_ptr = s;
|
||||
return token;
|
||||
}
|
||||
|
||||
char *
|
||||
grub_strtok (char *s, const char *delim)
|
||||
{
|
||||
static char *last;
|
||||
|
||||
return grub_strtok_r (s, delim, &last);
|
||||
}
|
||||
|
||||
int
|
||||
grub_isspace (int c)
|
||||
{
|
||||
@ -739,6 +833,9 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
|
||||
COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long));
|
||||
COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *)
|
||||
|| sizeof (int) == sizeof (void *));
|
||||
COMPILE_TIME_ASSERT (sizeof (size_t) == sizeof (unsigned)
|
||||
|| sizeof (size_t) == sizeof (unsigned long)
|
||||
|| sizeof (size_t) == sizeof (unsigned long long));
|
||||
|
||||
fmt = fmt0;
|
||||
while ((c = *fmt++) != 0)
|
||||
@ -773,11 +870,17 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
|
||||
fmt++;
|
||||
|
||||
c = *fmt++;
|
||||
if (c == 'z')
|
||||
{
|
||||
c = *fmt++;
|
||||
goto do_count;
|
||||
}
|
||||
if (c == 'l')
|
||||
c = *fmt++;
|
||||
if (c == 'l')
|
||||
c = *fmt++;
|
||||
|
||||
do_count:
|
||||
switch (c)
|
||||
{
|
||||
case 'p':
|
||||
@ -874,6 +977,14 @@ parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 'z')
|
||||
{
|
||||
c = *fmt++;
|
||||
if (sizeof (size_t) == sizeof (unsigned long))
|
||||
longfmt = 1;
|
||||
else if (sizeof (size_t) == sizeof (unsigned long long))
|
||||
longfmt = 2;
|
||||
}
|
||||
if (c == 'l')
|
||||
{
|
||||
c = *fmt++;
|
||||
@ -1050,6 +1161,8 @@ grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
|
||||
}
|
||||
|
||||
c = *fmt++;
|
||||
if (c == 'z')
|
||||
c = *fmt++;
|
||||
if (c == 'l')
|
||||
c = *fmt++;
|
||||
if (c == 'l')
|
||||
|
||||
@ -786,6 +786,39 @@ grub_mm_dump (unsigned lineno)
|
||||
grub_printf ("\n");
|
||||
}
|
||||
|
||||
void
|
||||
grub_mm_dump_regions (void)
|
||||
{
|
||||
grub_mm_region_t r;
|
||||
grub_mm_header_t p;
|
||||
grub_size_t num_blocks, sum_free, sum_alloc;
|
||||
|
||||
for (r = grub_mm_base; r; r = r->next)
|
||||
{
|
||||
num_blocks = 0;
|
||||
sum_free = 0;
|
||||
sum_alloc = 0;
|
||||
|
||||
p = (grub_mm_header_t) ALIGN_UP ((grub_addr_t) (r + 1), GRUB_MM_ALIGN);
|
||||
for (; (grub_addr_t) p < (grub_addr_t) (r+1) + r->size; p++, num_blocks++)
|
||||
{
|
||||
switch (p->magic)
|
||||
{
|
||||
case GRUB_MM_FREE_MAGIC:
|
||||
sum_free += p->size;
|
||||
break;
|
||||
case GRUB_MM_ALLOC_MAGIC:
|
||||
sum_alloc += p->size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
grub_printf ("Region %p (size %" PRIuGRUB_SIZE " blocks %" PRIuGRUB_SIZE " free %" PRIuGRUB_SIZE " alloc %" PRIuGRUB_SIZE ")\n\n",
|
||||
r, r->size, num_blocks, sum_free << GRUB_MM_ALIGN_LOG2, sum_alloc << GRUB_MM_ALIGN_LOG2);
|
||||
}
|
||||
|
||||
grub_printf ("\n");
|
||||
}
|
||||
|
||||
void *
|
||||
grub_debug_calloc (const char *file, int line, grub_size_t nmemb, grub_size_t size)
|
||||
{
|
||||
|
||||
137
grub-core/kern/powerpc/ieee1275/ieee1275.c
Normal file
137
grub-core/kern/powerpc/ieee1275/ieee1275.c
Normal file
@ -0,0 +1,137 @@
|
||||
/* ieee1275.c - Access the Open Firmware client interface. */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2020, 2021, 2022, 2023, 2024, 2025 IBM Corporation
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <grub/ieee1275/ieee1275.h>
|
||||
#include <grub/powerpc/ieee1275/ieee1275.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
grub_int32_t
|
||||
grub_ieee1275_test (const char *interface_name)
|
||||
{
|
||||
struct test_args
|
||||
{
|
||||
struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
|
||||
grub_ieee1275_cell_t name; /* The interface name. */
|
||||
grub_ieee1275_cell_t missing;
|
||||
} args;
|
||||
|
||||
INIT_IEEE1275_COMMON (&args.common, "test", 1, 1);
|
||||
args.name = (grub_ieee1275_cell_t) interface_name;
|
||||
|
||||
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||||
return -1;
|
||||
|
||||
if (args.missing == IEEE1275_CELL_INVALID)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_int32_t
|
||||
grub_ieee1275_pks_max_object_size (grub_uint32_t *result)
|
||||
{
|
||||
struct mos_args
|
||||
{
|
||||
struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
|
||||
grub_ieee1275_cell_t size; /* The maximum object size for a PKS object. */
|
||||
} args;
|
||||
|
||||
INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_MAX_OBJ_INTERFACE, 0, 1);
|
||||
|
||||
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||||
return -1;
|
||||
|
||||
if (args.size == IEEE1275_CELL_INVALID || args.size == 0)
|
||||
return -1;
|
||||
|
||||
*result = args.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_int32_t
|
||||
grub_ieee1275_pks_read_object (const grub_uint32_t consumer, const char *label,
|
||||
const grub_uint32_t label_len, const grub_uint32_t buffer_len,
|
||||
grub_uint8_t *buffer, grub_uint32_t *data_len,
|
||||
grub_uint32_t *policies)
|
||||
{
|
||||
struct pks_read_args
|
||||
{
|
||||
struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
|
||||
grub_ieee1275_cell_t consumer; /* The object belonging to consumer with the label. */
|
||||
grub_ieee1275_cell_t label; /* Object label buffer logical real address. */
|
||||
grub_ieee1275_cell_t label_len; /* The byte length of the object label. */
|
||||
grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
|
||||
grub_ieee1275_cell_t buffer_len; /* Length of the output buffer. */
|
||||
grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
|
||||
grub_ieee1275_cell_t policies; /* The object policies. */
|
||||
grub_int32_t rc; /* The return code. */
|
||||
} args;
|
||||
|
||||
INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_OBJ_INTERFACE, 5, 3);
|
||||
args.consumer = consumer;
|
||||
args.label_len = label_len;
|
||||
args.buffer_len = buffer_len;
|
||||
args.label = (grub_ieee1275_cell_t) label;
|
||||
args.buffer = (grub_ieee1275_cell_t) buffer;
|
||||
|
||||
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||||
return -1;
|
||||
|
||||
if (args.data_len == IEEE1275_CELL_INVALID)
|
||||
return -1;
|
||||
|
||||
*data_len = args.data_len;
|
||||
*policies = args.policies;
|
||||
|
||||
return args.rc;
|
||||
}
|
||||
|
||||
grub_int32_t
|
||||
grub_ieee1275_pks_read_sbvar (const grub_uint32_t sbvar_flags, const grub_uint32_t sbvar_type,
|
||||
const grub_uint32_t buffer_len, grub_uint8_t *buffer,
|
||||
grub_size_t *data_len)
|
||||
{
|
||||
struct pks_read_sbvar_args
|
||||
{
|
||||
struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
|
||||
grub_ieee1275_cell_t sbvar_flags; /* The sbvar operation flags. */
|
||||
grub_ieee1275_cell_t sbvar_type; /* The sbvar being requested. */
|
||||
grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
|
||||
grub_ieee1275_cell_t buffer_len; /* Length of the Output buffer. */
|
||||
grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
|
||||
grub_int32_t rc; /* The return code. */
|
||||
} args;
|
||||
|
||||
INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_SBVAR_INTERFACE, 4, 2);
|
||||
args.sbvar_flags = sbvar_flags;
|
||||
args.sbvar_type = sbvar_type;
|
||||
args.buffer_len = buffer_len;
|
||||
args.buffer = (grub_ieee1275_cell_t) buffer;
|
||||
|
||||
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||||
return -1;
|
||||
|
||||
if (args.data_len == IEEE1275_CELL_INVALID)
|
||||
return -1;
|
||||
|
||||
*data_len = args.data_len;
|
||||
|
||||
return args.rc;
|
||||
}
|
||||
333
grub-core/kern/powerpc/ieee1275/platform_keystore.c
Normal file
333
grub-core/kern/powerpc/ieee1275/platform_keystore.c
Normal file
@ -0,0 +1,333 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2022, 2023, 2024, 2025 IBM Corporation
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/mm.h>
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/lockdown.h>
|
||||
#include <grub/ieee1275/ieee1275.h>
|
||||
#include <grub/powerpc/ieee1275/ieee1275.h>
|
||||
#include <grub/powerpc/ieee1275/platform_keystore.h>
|
||||
|
||||
/* PKS object maximum size. */
|
||||
static grub_uint32_t pks_max_object_size = 0;
|
||||
|
||||
/* Platform KeyStore db and dbx. */
|
||||
static grub_pks_t pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0,
|
||||
.dbx_entries = 0, .db_exists = true};
|
||||
/*
|
||||
* pks_use_keystore: Key Management Modes
|
||||
* False: Static key management (use built-in Keys). This is default.
|
||||
* True: Dynamic key management (use Platform KeySotre).
|
||||
*/
|
||||
static bool pks_use_keystore = false;
|
||||
|
||||
/*
|
||||
* Reads the Globally Unique Identifier (GUID), EFI Signature Database (ESD),
|
||||
* and its size from the Platform KeyStore EFI Signature List (ESL), then
|
||||
* stores them into the PKS Signature Database (SD) (i.e., pks_sd buffer
|
||||
* and pks_sd entries) in the GRUB.
|
||||
*/
|
||||
static grub_err_t
|
||||
_esl_to_esd (const grub_uint8_t *esl_data, grub_size_t esl_size,
|
||||
const grub_size_t signature_size, const grub_packed_guid_t *guid,
|
||||
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
|
||||
{
|
||||
grub_esd_t *esd;
|
||||
grub_pks_sd_t *signature = *pks_sd;
|
||||
grub_uint32_t entries = *pks_sd_entries;
|
||||
grub_size_t data_size, offset = 0;
|
||||
|
||||
/* Reads the ESD from ESL. */
|
||||
while (esl_size > 0)
|
||||
{
|
||||
esd = (grub_esd_t *) (esl_data + offset);
|
||||
data_size = signature_size - sizeof (grub_esd_t);
|
||||
|
||||
signature = grub_realloc (signature, (entries + 1) * sizeof (grub_pks_sd_t));
|
||||
if (signature == NULL)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||||
|
||||
signature[entries].data = grub_malloc (data_size * sizeof (grub_uint8_t));
|
||||
if (signature[entries].data == NULL)
|
||||
{
|
||||
/* Allocated memory will be freed by grub_pks_free_data(). */
|
||||
*pks_sd = signature;
|
||||
*pks_sd_entries = entries + 1;
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||||
}
|
||||
|
||||
grub_memcpy (signature[entries].data, esd->signature_data, data_size);
|
||||
signature[entries].data_size = data_size;
|
||||
signature[entries].guid = *guid;
|
||||
entries++;
|
||||
esl_size -= signature_size;
|
||||
offset += signature_size;
|
||||
}
|
||||
|
||||
*pks_sd = signature;
|
||||
*pks_sd_entries = entries;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Extract the ESD after removing the ESL header from ESL. */
|
||||
static grub_err_t
|
||||
esl_to_esd (const grub_uint8_t *esl_data, grub_size_t *next_esl,
|
||||
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
|
||||
{
|
||||
grub_packed_guid_t guid;
|
||||
grub_esl_t *esl;
|
||||
grub_size_t offset, esl_size, signature_size, signature_header_size;
|
||||
|
||||
/* Convert the ESL data into the ESL. */
|
||||
esl = (grub_esl_t *) esl_data;
|
||||
if (*next_esl < sizeof (grub_esl_t) || esl == NULL)
|
||||
return grub_error (GRUB_ERR_BUG, "invalid ESL");
|
||||
|
||||
esl_size = grub_le_to_cpu32 (esl->signature_list_size);
|
||||
signature_header_size = grub_le_to_cpu32 (esl->signature_header_size);
|
||||
signature_size = grub_le_to_cpu32 (esl->signature_size);
|
||||
grub_memcpy (&guid, &esl->signature_type, sizeof (grub_packed_guid_t));
|
||||
|
||||
if (esl_size < sizeof (grub_esl_t) || esl_size > *next_esl)
|
||||
return grub_error (GRUB_ERR_BUG, "invalid ESL size (%u)\n", esl_size);
|
||||
|
||||
*next_esl = esl_size;
|
||||
offset = sizeof (grub_esl_t) + signature_header_size;
|
||||
esl_size = esl_size - offset;
|
||||
|
||||
return _esl_to_esd (esl_data + offset, esl_size, signature_size, &guid,
|
||||
pks_sd, pks_sd_entries);
|
||||
}
|
||||
|
||||
/*
|
||||
* Import the EFI Signature Database (ESD) and the number of ESD from the ESL
|
||||
* into the pks_sd buffer and pks_sd entries.
|
||||
*/
|
||||
static grub_err_t
|
||||
pks_sd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size,
|
||||
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
|
||||
{
|
||||
grub_err_t rc;
|
||||
grub_size_t next_esl = esl_size;
|
||||
|
||||
do
|
||||
{
|
||||
rc = esl_to_esd (esl_data, &next_esl, pks_sd, pks_sd_entries);
|
||||
if (rc != GRUB_ERR_NONE)
|
||||
break;
|
||||
|
||||
esl_data += next_esl;
|
||||
esl_size -= next_esl;
|
||||
next_esl = esl_size;
|
||||
}
|
||||
while (esl_size > 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Read the secure boot version from PKS as an object. Caller must free result. */
|
||||
static grub_err_t
|
||||
read_sbversion_from_pks (grub_uint8_t **out)
|
||||
{
|
||||
grub_int32_t rc;
|
||||
grub_uint32_t outlen = 0, policy = 0;
|
||||
|
||||
*out = grub_malloc (pks_max_object_size);
|
||||
if (*out == NULL)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||||
|
||||
rc = grub_ieee1275_pks_read_object (GRUB_PKS_CONSUMER_FW, GRUB_SB_VERSION_KEY_NAME,
|
||||
GRUB_SB_VERSION_KEY_LEN, pks_max_object_size, *out,
|
||||
&outlen, &policy);
|
||||
if (rc < 0)
|
||||
{
|
||||
grub_free (*out);
|
||||
return grub_error (GRUB_ERR_READ_ERROR, "SB version read failed (%d)\n", rc);
|
||||
}
|
||||
|
||||
if (outlen != 1 || (**out >= 2))
|
||||
{
|
||||
grub_free (*out);
|
||||
return grub_error (GRUB_ERR_BAD_NUMBER, "found unexpected SB version: %u\n", **out);
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the secure boot variable from PKS, unpacks it, read the ESD from ESL,
|
||||
* and store the information in the pks_sd buffer.
|
||||
*/
|
||||
static grub_err_t
|
||||
read_sbvar_from_pks (const grub_uint32_t sbvarflags, const grub_uint32_t sbvartype,
|
||||
grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
|
||||
{
|
||||
grub_int32_t rc;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
grub_uint8_t *esl_data = NULL;
|
||||
grub_size_t esl_data_size = 0;
|
||||
|
||||
esl_data = grub_malloc (pks_max_object_size);
|
||||
if (esl_data == NULL)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
|
||||
|
||||
rc = grub_ieee1275_pks_read_sbvar (sbvarflags, sbvartype, pks_max_object_size,
|
||||
esl_data, &esl_data_size);
|
||||
if (rc == IEEE1275_CELL_NOT_FOUND)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "secure boot variable %s not found (%d)",
|
||||
(sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
|
||||
goto fail;
|
||||
}
|
||||
else if (rc < 0)
|
||||
{
|
||||
err = grub_error (GRUB_ERR_READ_ERROR, "secure boot variable %s reading (%d)",
|
||||
(sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (esl_data_size > 0)
|
||||
err = pks_sd_from_esl (esl_data, esl_data_size, pks_sd, pks_sd_entries);
|
||||
else
|
||||
err = GRUB_ERR_BAD_NUMBER;
|
||||
|
||||
fail:
|
||||
grub_free (esl_data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test the availability of PKS support. If PKS support is avaialble and objects
|
||||
* present, it reads the secure boot version (SB_VERSION) from PKS.
|
||||
*
|
||||
* SB_VERSION: Key Management Mode
|
||||
* 1 - Enable dynamic key management mode. Read the db and dbx variables from PKS,
|
||||
* and use them for signature verification.
|
||||
* 0 - Enable static key management mode. Read keys from the GRUB ELF Note and use
|
||||
* it for signature verification.
|
||||
*/
|
||||
static bool
|
||||
is_pks_present (void)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_int32_t rc;
|
||||
grub_uint8_t *data = NULL;
|
||||
bool ret = false;
|
||||
|
||||
rc = grub_ieee1275_test (GRUB_PKS_MAX_OBJ_INTERFACE);
|
||||
if (rc < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_FIRMWARE, "firmware doesn't have PKS support\n");
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size);
|
||||
if (rc < 0)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_NUMBER, "PKS support is there but it has zero objects\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
err = read_sbversion_from_pks (&data);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If *data == 1, use dynamic key management and read the keys from the PKS.
|
||||
* Else, use static key management and read the keys from the GRUB ELF Note.
|
||||
*/
|
||||
ret = ((*data == 1) ? true : false);
|
||||
|
||||
grub_free (data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Free allocated memory. */
|
||||
void
|
||||
grub_pks_free_data (void)
|
||||
{
|
||||
grub_size_t i;
|
||||
|
||||
for (i = 0; i < pks_keystore.db_entries; i++)
|
||||
grub_free (pks_keystore.db[i].data);
|
||||
|
||||
for (i = 0; i < pks_keystore.dbx_entries; i++)
|
||||
grub_free (pks_keystore.dbx[i].data);
|
||||
|
||||
grub_free (pks_keystore.db);
|
||||
grub_free (pks_keystore.dbx);
|
||||
grub_memset (&pks_keystore, 0, sizeof (grub_pks_t));
|
||||
}
|
||||
|
||||
grub_pks_t *
|
||||
grub_pks_get_keystore (void)
|
||||
{
|
||||
return (pks_use_keystore == true) ? &pks_keystore : NULL;
|
||||
}
|
||||
|
||||
/* Initialization of the Platform KeyStore. */
|
||||
void
|
||||
grub_pks_keystore_init (void)
|
||||
{
|
||||
grub_err_t rc_db, rc_dbx;
|
||||
|
||||
grub_dprintf ("ieee1275", "trying to load Platform KeyStore\n");
|
||||
|
||||
if (is_pks_present () == false)
|
||||
{
|
||||
grub_dprintf ("ieee1275", "Platform PKS is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* When read db from PKS, there are three scenarios
|
||||
* 1. db fully loaded from PKS
|
||||
* 2. db partially loaded from PKS
|
||||
* 3. no keys are loaded from db (if db does not exist in PKS), default to
|
||||
* built-in keys (static keys)
|
||||
* each of these scenarios, the db keys are checked against dbx.
|
||||
*/
|
||||
rc_db = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DB, &pks_keystore.db, &pks_keystore.db_entries);
|
||||
if (rc_db == GRUB_ERR_FILE_NOT_FOUND)
|
||||
pks_keystore.db_exists = false;
|
||||
|
||||
/*
|
||||
* Read dbx from PKS. If dbx is not completely loaded from PKS, then this
|
||||
* could lead to the loading of vulnerable GRUB modules and kernel binaries.
|
||||
* So, this should be prevented by freeing up loaded dbx and db.
|
||||
*/
|
||||
rc_dbx = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DBX, &pks_keystore.dbx, &pks_keystore.dbx_entries);
|
||||
if (rc_dbx == GRUB_ERR_FILE_NOT_FOUND || rc_dbx == GRUB_ERR_BAD_NUMBER)
|
||||
rc_dbx = GRUB_ERR_NONE;
|
||||
|
||||
if (rc_dbx != GRUB_ERR_NONE)
|
||||
grub_pks_free_data ();
|
||||
|
||||
/*
|
||||
* At this point, it's evident that PKS infrastructure exists, so the PKS
|
||||
* keystore must be used for validating appended signatures.
|
||||
*/
|
||||
pks_use_keystore = true;
|
||||
}
|
||||
360
grub-core/kern/xen/cmdline.c
Normal file
360
grub-core/kern/xen/cmdline.c
Normal file
@ -0,0 +1,360 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/env.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/xen.h>
|
||||
#include <grub/err.h>
|
||||
|
||||
enum splitter_state
|
||||
{
|
||||
SPLITTER_NORMAL = 0x0,
|
||||
SPLITTER_HIT_BACKSLASH = 0x1,
|
||||
SPLITTER_IN_SINGLE_QUOTES = 0x2,
|
||||
SPLITTER_IN_DOUBLE_QUOTES = 0x4,
|
||||
};
|
||||
typedef enum splitter_state splitter_state_t;
|
||||
|
||||
/*
|
||||
* The initial size of the current_word buffer. The buffer may be resized as
|
||||
* needed.
|
||||
*/
|
||||
#define PARSER_BASE_WORD_SIZE 32
|
||||
|
||||
struct parser_state
|
||||
{
|
||||
char **words;
|
||||
grub_size_t words_count;
|
||||
char *current_word;
|
||||
grub_size_t current_word_len;
|
||||
grub_size_t current_word_pos;
|
||||
};
|
||||
typedef struct parser_state parser_state_t;
|
||||
|
||||
static grub_err_t
|
||||
append_char_to_word (parser_state_t *ps, char c, bool allow_null)
|
||||
{
|
||||
/*
|
||||
* We ban any chars that are not in the ASCII printable range. If
|
||||
* allow_null == true, we make an exception for NUL. (This is needed so that
|
||||
* append_word_to_list can add a NUL terminator to the word).
|
||||
*/
|
||||
if (!grub_isprint (c) && allow_null == false)
|
||||
return GRUB_ERR_BAD_ARGUMENT;
|
||||
else if (allow_null == true && c != '\0')
|
||||
return GRUB_ERR_BAD_ARGUMENT;
|
||||
|
||||
if (ps->current_word_pos == ps->current_word_len)
|
||||
{
|
||||
ps->current_word = grub_realloc (ps->current_word, ps->current_word_len *= 2);
|
||||
if (ps->current_word == NULL)
|
||||
{
|
||||
ps->current_word_len /= 2;
|
||||
return grub_errno;
|
||||
}
|
||||
}
|
||||
|
||||
ps->current_word[ps->current_word_pos++] = c;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
append_word_to_list (parser_state_t *ps)
|
||||
{
|
||||
/* No-op on empty words. */
|
||||
if (ps->current_word_pos == 0)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
if (append_char_to_word (ps, '\0', true) != GRUB_ERR_NONE)
|
||||
grub_fatal ("couldn't append NUL terminator to word during Xen cmdline parsing");
|
||||
|
||||
ps->current_word_len = grub_strlen (ps->current_word) + 1;
|
||||
ps->current_word = grub_realloc (ps->current_word, ps->current_word_len);
|
||||
if (ps->current_word == NULL)
|
||||
return grub_errno;
|
||||
ps->words = grub_realloc (ps->words, ++ps->words_count * sizeof (char *));
|
||||
if (ps->words == NULL)
|
||||
return grub_errno;
|
||||
ps->words[ps->words_count - 1] = ps->current_word;
|
||||
|
||||
ps->current_word_len = PARSER_BASE_WORD_SIZE;
|
||||
ps->current_word_pos = 0;
|
||||
ps->current_word = grub_malloc (ps->current_word_len);
|
||||
if (ps->current_word == NULL)
|
||||
return grub_errno;
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_key_safe (char *key, grub_size_t len)
|
||||
{
|
||||
grub_size_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (!grub_isalpha (key[i]) && key[i] != '_')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
grub_parse_xen_cmdline (void)
|
||||
{
|
||||
parser_state_t ps = {0};
|
||||
splitter_state_t ss = SPLITTER_NORMAL;
|
||||
|
||||
const char *cmdline = (const char *) grub_xen_start_page_addr->cmd_line;
|
||||
grub_size_t cmdline_len;
|
||||
bool cmdline_valid = false;
|
||||
char **param_keys = NULL;
|
||||
char **param_vals = NULL;
|
||||
grub_size_t param_dict_len = 0;
|
||||
grub_size_t param_dict_pos = 0;
|
||||
char current_char = '\0';
|
||||
grub_size_t i = 0;
|
||||
|
||||
/*
|
||||
* The following algorithm is used to parse the Xen command line:
|
||||
*
|
||||
* - The command line is split into space-separated words.
|
||||
* - Single and double quotes may be used to suppress the splitting
|
||||
* behavior of spaces.
|
||||
* - Double quotes are appended to the current word verbatim if they
|
||||
* appear within a single-quoted string portion, and vice versa.
|
||||
* - Backslashes may be used to cause the next character to be
|
||||
* appended to the current word verbatim. This is only useful when
|
||||
* used to escape quotes, spaces, and backslashes, but for simplicity
|
||||
* we allow backslash-escaping anything.
|
||||
* - After splitting the command line into words, each word is checked to
|
||||
* see if it contains an equals sign.
|
||||
* - If it does, it is split on the equals sign into a key-value pair. The
|
||||
* key is then treated as an variable name, and the value is treated as
|
||||
* the variable's value.
|
||||
* - If it does not, the entire word is treated as a variable name. The
|
||||
* variable's value is implicitly considered to be `1`.
|
||||
* - All variables detected on the command line are checked to see if their
|
||||
* names begin with the string `xen_grub_env_`. Variables that do not pass
|
||||
* this check are discarded, variables that do pass this check are
|
||||
* exported so they are available to the GRUB configuration.
|
||||
*
|
||||
* This behavior is intended to somewhat mimic the splitter behavior in Bash
|
||||
* and in GRUB's config file parser.
|
||||
*/
|
||||
|
||||
ps.current_word_len = PARSER_BASE_WORD_SIZE;
|
||||
ps.current_word = grub_malloc (ps.current_word_len);
|
||||
if (ps.current_word == NULL)
|
||||
goto cleanup_main;
|
||||
|
||||
for (i = 0; i < GRUB_XEN_MAX_GUEST_CMDLINE; i++)
|
||||
{
|
||||
if (cmdline[i] == '\0')
|
||||
{
|
||||
cmdline_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmdline_valid == false)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"command line from Xen is not NUL-terminated");
|
||||
grub_print_error ();
|
||||
goto cleanup_main;
|
||||
}
|
||||
|
||||
cmdline_len = grub_strlen (cmdline);
|
||||
for (i = 0; i < cmdline_len; i++)
|
||||
{
|
||||
current_char = cmdline[i];
|
||||
|
||||
/*
|
||||
* If the previous character was a backslash, append the current
|
||||
* character to the word verbatim
|
||||
*/
|
||||
if (ss & SPLITTER_HIT_BACKSLASH)
|
||||
{
|
||||
ss &= ~SPLITTER_HIT_BACKSLASH;
|
||||
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
|
||||
goto cleanup_main;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (current_char)
|
||||
{
|
||||
case '\\':
|
||||
/* Backslashes escape arbitrary characters. */
|
||||
ss |= SPLITTER_HIT_BACKSLASH;
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
/*
|
||||
* Single quotes suppress word splitting and double quoting until
|
||||
* the next single quote is encountered.
|
||||
*/
|
||||
if (ss & SPLITTER_IN_DOUBLE_QUOTES)
|
||||
{
|
||||
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
|
||||
goto cleanup_main;
|
||||
break;
|
||||
}
|
||||
|
||||
ss ^= SPLITTER_IN_SINGLE_QUOTES;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
/*
|
||||
* Double quotes suppress word splitting and single quoting until
|
||||
* the next double quote is encountered.
|
||||
*/
|
||||
if (ss & SPLITTER_IN_SINGLE_QUOTES)
|
||||
{
|
||||
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
|
||||
goto cleanup_main;
|
||||
break;
|
||||
}
|
||||
|
||||
ss ^= SPLITTER_IN_DOUBLE_QUOTES;
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
/* Spaces separate words in the command line from each other. */
|
||||
if (ss & SPLITTER_IN_SINGLE_QUOTES ||
|
||||
ss & SPLITTER_IN_DOUBLE_QUOTES)
|
||||
{
|
||||
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
|
||||
goto cleanup_main;
|
||||
break;
|
||||
}
|
||||
|
||||
if (append_word_to_list (&ps) != GRUB_ERR_NONE)
|
||||
goto cleanup_main;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (append_char_to_word (&ps, current_char, false) != GRUB_ERR_NONE)
|
||||
goto cleanup_main;
|
||||
}
|
||||
}
|
||||
|
||||
if (append_word_to_list (&ps) != GRUB_ERR_NONE)
|
||||
goto cleanup_main;
|
||||
|
||||
param_keys = grub_malloc (ps.words_count * sizeof (char *));
|
||||
if (param_keys == NULL)
|
||||
goto cleanup_main;
|
||||
param_vals = grub_malloc (ps.words_count * sizeof (char *));
|
||||
if (param_vals == NULL)
|
||||
goto cleanup_main;
|
||||
|
||||
for (i = 0; i < ps.words_count; i++)
|
||||
{
|
||||
char *eq_pos;
|
||||
|
||||
ps.current_word = ps.words[i];
|
||||
ps.current_word_len = grub_strlen (ps.current_word) + 1;
|
||||
eq_pos = grub_strchr (ps.current_word, '=');
|
||||
|
||||
if (eq_pos != NULL)
|
||||
{
|
||||
/*
|
||||
* Both pre_eq_len and post_eq_len represent substring lengths
|
||||
* without a NUL terminator.
|
||||
*/
|
||||
grub_size_t pre_eq_len = (grub_size_t) (eq_pos - ps.current_word);
|
||||
/*
|
||||
* ps.current_word_len includes the NUL terminator, so we subtract
|
||||
* one to get rid of the terminator, and one more to get rid of the
|
||||
* equals sign.
|
||||
*/
|
||||
grub_size_t post_eq_len = (ps.current_word_len - 2) - pre_eq_len;
|
||||
|
||||
if (is_key_safe (ps.current_word, pre_eq_len) == true)
|
||||
{
|
||||
param_dict_pos = param_dict_len++;
|
||||
param_keys[param_dict_pos] = grub_malloc (pre_eq_len + 1);
|
||||
if (param_keys == NULL)
|
||||
goto cleanup_main;
|
||||
param_vals[param_dict_pos] = grub_malloc (post_eq_len + 1);
|
||||
if (param_vals == NULL)
|
||||
goto cleanup_main;
|
||||
|
||||
grub_strncpy (param_keys[param_dict_pos], ps.current_word, pre_eq_len);
|
||||
grub_strncpy (param_vals[param_dict_pos],
|
||||
ps.current_word + pre_eq_len + 1, post_eq_len);
|
||||
param_keys[param_dict_pos][pre_eq_len] = '\0';
|
||||
param_vals[param_dict_pos][post_eq_len] = '\0';
|
||||
}
|
||||
}
|
||||
else if (is_key_safe (ps.current_word, ps.current_word_len - 1) == true)
|
||||
{
|
||||
param_dict_pos = param_dict_len++;
|
||||
param_keys[param_dict_pos] = grub_malloc (ps.current_word_len);
|
||||
if (param_keys == NULL)
|
||||
goto cleanup_main;
|
||||
param_vals[param_dict_pos] = grub_zalloc (2);
|
||||
if (param_vals == NULL)
|
||||
goto cleanup_main;
|
||||
|
||||
grub_strncpy (param_keys[param_dict_pos], ps.current_word,
|
||||
ps.current_word_len);
|
||||
if (param_keys[param_dict_pos][ps.current_word_len - 1] != '\0' )
|
||||
grub_fatal ("NUL terminator missing from key during Xen cmdline parsing");
|
||||
*param_vals[param_dict_pos] = '1';
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < param_dict_len; i++)
|
||||
{
|
||||
/*
|
||||
* Find keys that start with "xen_grub_env_" and export them
|
||||
* as environment variables.
|
||||
*/
|
||||
if (grub_strncmp (param_keys[i],
|
||||
"xen_grub_env_",
|
||||
sizeof ("xen_grub_env_") - 1) != 0)
|
||||
continue;
|
||||
|
||||
if (grub_env_set (param_keys[i], param_vals[i]) != GRUB_ERR_NONE)
|
||||
{
|
||||
grub_printf ("warning: could not set environment variable `%s' to value `%s'\n",
|
||||
param_keys[i], param_vals[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (grub_env_export (param_keys[i]) != GRUB_ERR_NONE)
|
||||
grub_printf ("warning: could not export environment variable `%s'",
|
||||
param_keys[i]);
|
||||
}
|
||||
|
||||
cleanup_main:
|
||||
for (i = 0; i < ps.words_count; i++)
|
||||
grub_free (ps.words[i]);
|
||||
|
||||
for (i = 0; i < param_dict_len; i++)
|
||||
{
|
||||
grub_free (param_keys[i]);
|
||||
grub_free (param_vals[i]);
|
||||
}
|
||||
|
||||
grub_free (param_keys);
|
||||
grub_free (param_vals);
|
||||
grub_free (ps.words);
|
||||
}
|
||||
@ -581,6 +581,8 @@ grub_machine_init (void)
|
||||
grub_xendisk_init ();
|
||||
|
||||
grub_boot_init ();
|
||||
|
||||
grub_parse_xen_cmdline ();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
52
grub-core/lib/argon2.c
Normal file
52
grub-core/lib/argon2.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/crypto.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
gcry_err_code_t
|
||||
grub_crypto_argon2 (int subalgo,
|
||||
const unsigned long *param, unsigned int paramlen,
|
||||
const void *password, grub_size_t passwordlen,
|
||||
const void *salt, grub_size_t saltlen,
|
||||
const void *key, grub_size_t keylen,
|
||||
const void *ad, grub_size_t adlen,
|
||||
grub_size_t resultlen, void *result)
|
||||
{
|
||||
gcry_kdf_hd_t hd = {0};
|
||||
gpg_err_code_t err;
|
||||
|
||||
if (saltlen == 0)
|
||||
return GPG_ERR_INV_VALUE;
|
||||
|
||||
err = _gcry_kdf_open (&hd, GRUB_GCRY_KDF_ARGON2, subalgo, param, paramlen,
|
||||
password, passwordlen, salt, saltlen, key, keylen,
|
||||
ad, adlen);
|
||||
if (err != GPG_ERR_NO_ERROR)
|
||||
return err;
|
||||
|
||||
err = _gcry_kdf_compute (hd, NULL);
|
||||
if (err == GPG_ERR_NO_ERROR)
|
||||
err = _gcry_kdf_final (hd, resultlen, result);
|
||||
|
||||
_gcry_kdf_close (hd);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -100,8 +100,8 @@ _gpgrt_b64dec_start (const char *title)
|
||||
/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
|
||||
new length of the buffer at R_NBYTES. */
|
||||
gpg_err_code_t
|
||||
_gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
|
||||
size_t *r_nbytes)
|
||||
_gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, grub_size_t length,
|
||||
grub_size_t *r_nbytes)
|
||||
{
|
||||
enum decoder_states ds = state->idx;
|
||||
unsigned char val = state->radbuf[0];
|
||||
|
||||
@ -31,7 +31,9 @@ struct grub_crypto_hmac_handle
|
||||
{
|
||||
const struct gcry_md_spec *md;
|
||||
void *ctx;
|
||||
void *opad;
|
||||
void *ctx2;
|
||||
void *ctx_cache;
|
||||
void *ctx2_cache;
|
||||
};
|
||||
|
||||
static gcry_cipher_spec_t *grub_ciphers = NULL;
|
||||
@ -170,6 +172,10 @@ grub_md_unregister (gcry_md_spec_t *cipher)
|
||||
}
|
||||
}
|
||||
|
||||
struct gcry_pk_spec *grub_crypto_pk_dsa;
|
||||
struct gcry_pk_spec *grub_crypto_pk_ecdsa;
|
||||
struct gcry_pk_spec *grub_crypto_pk_rsa;
|
||||
|
||||
void
|
||||
grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in,
|
||||
grub_size_t inlen)
|
||||
@ -439,7 +445,8 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
|
||||
{
|
||||
grub_uint8_t *helpkey = NULL;
|
||||
grub_uint8_t *ipad = NULL, *opad = NULL;
|
||||
void *ctx = NULL;
|
||||
void *ctx = NULL, *ctx2 = NULL;
|
||||
void *ctx_cache = NULL, *ctx2_cache = NULL;
|
||||
struct grub_crypto_hmac_handle *ret = NULL;
|
||||
unsigned i;
|
||||
|
||||
@ -450,6 +457,18 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
|
||||
if (!ctx)
|
||||
goto err;
|
||||
|
||||
ctx2 = grub_malloc (md->contextsize);
|
||||
if (!ctx2)
|
||||
goto err;
|
||||
|
||||
ctx_cache = grub_malloc (md->contextsize);
|
||||
if (!ctx_cache)
|
||||
goto err;
|
||||
|
||||
ctx2_cache = grub_malloc (md->contextsize);
|
||||
if (!ctx2_cache)
|
||||
goto err;
|
||||
|
||||
if ( keylen > md->blocksize )
|
||||
{
|
||||
helpkey = grub_malloc (md->mdlen);
|
||||
@ -479,26 +498,40 @@ grub_crypto_hmac_init (const struct gcry_md_spec *md,
|
||||
grub_free (helpkey);
|
||||
helpkey = NULL;
|
||||
|
||||
/* inner pad */
|
||||
md->init (ctx, 0);
|
||||
|
||||
md->write (ctx, ipad, md->blocksize); /* inner pad */
|
||||
md->write (ctx, ipad, md->blocksize);
|
||||
grub_memcpy (ctx_cache, ctx, md->contextsize);
|
||||
grub_memset (ipad, 0, md->blocksize);
|
||||
grub_free (ipad);
|
||||
ipad = NULL;
|
||||
|
||||
/* outer pad */
|
||||
md->init (ctx2, 0);
|
||||
md->write (ctx2, opad, md->blocksize);
|
||||
grub_memcpy (ctx2_cache, ctx2, md->contextsize);
|
||||
grub_memset (opad, 0, md->blocksize);
|
||||
grub_free (opad);
|
||||
opad = NULL;
|
||||
|
||||
ret = grub_malloc (sizeof (*ret));
|
||||
if (!ret)
|
||||
goto err;
|
||||
|
||||
ret->md = md;
|
||||
ret->ctx = ctx;
|
||||
ret->opad = opad;
|
||||
ret->ctx2 = ctx2;
|
||||
ret->ctx_cache = ctx_cache;
|
||||
ret->ctx2_cache = ctx2_cache;
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
grub_free (helpkey);
|
||||
grub_free (ctx);
|
||||
grub_free (ctx2);
|
||||
grub_free (ctx_cache);
|
||||
grub_free (ctx2_cache);
|
||||
grub_free (ipad);
|
||||
grub_free (opad);
|
||||
return NULL;
|
||||
@ -512,37 +545,48 @@ grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd,
|
||||
hnd->md->write (hnd->ctx, data, datalen);
|
||||
}
|
||||
|
||||
gcry_err_code_t
|
||||
void
|
||||
grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
|
||||
{
|
||||
grub_uint8_t *p;
|
||||
grub_uint8_t *ctx2;
|
||||
grub_crypto_hmac_final (hnd, out);
|
||||
grub_crypto_hmac_free (hnd);
|
||||
}
|
||||
|
||||
ctx2 = grub_malloc (hnd->md->contextsize);
|
||||
if (!ctx2)
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
void
|
||||
grub_crypto_hmac_reset (struct grub_crypto_hmac_handle *hnd)
|
||||
{
|
||||
grub_memcpy (hnd->ctx, hnd->ctx_cache, hnd->md->contextsize);
|
||||
grub_memcpy (hnd->ctx2, hnd->ctx2_cache, hnd->md->contextsize);
|
||||
}
|
||||
|
||||
void
|
||||
grub_crypto_hmac_final (struct grub_crypto_hmac_handle *hnd, void *out)
|
||||
{
|
||||
grub_uint8_t *p;
|
||||
|
||||
hnd->md->final (hnd->ctx);
|
||||
hnd->md->read (hnd->ctx);
|
||||
p = hnd->md->read (hnd->ctx);
|
||||
|
||||
hnd->md->init (ctx2, 0);
|
||||
hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize);
|
||||
hnd->md->write (ctx2, p, hnd->md->mdlen);
|
||||
hnd->md->final (ctx2);
|
||||
grub_memset (hnd->opad, 0, hnd->md->blocksize);
|
||||
grub_free (hnd->opad);
|
||||
hnd->md->write (hnd->ctx2, p, hnd->md->mdlen);
|
||||
hnd->md->final (hnd->ctx2);
|
||||
|
||||
grub_memcpy (out, hnd->md->read (hnd->ctx2), hnd->md->mdlen);
|
||||
}
|
||||
|
||||
void
|
||||
grub_crypto_hmac_free (struct grub_crypto_hmac_handle *hnd)
|
||||
{
|
||||
grub_memset (hnd->ctx, 0, hnd->md->contextsize);
|
||||
grub_free (hnd->ctx);
|
||||
|
||||
grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen);
|
||||
grub_memset (ctx2, 0, hnd->md->contextsize);
|
||||
grub_free (ctx2);
|
||||
|
||||
grub_memset (hnd->ctx2, 0, hnd->md->contextsize);
|
||||
grub_free (hnd->ctx2);
|
||||
grub_memset (hnd->ctx_cache, 0, hnd->md->contextsize);
|
||||
grub_free (hnd->ctx_cache);
|
||||
grub_memset (hnd->ctx2_cache, 0, hnd->md->contextsize);
|
||||
grub_free (hnd->ctx2_cache);
|
||||
grub_memset (hnd, 0, sizeof (*hnd));
|
||||
grub_free (hnd);
|
||||
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
gcry_err_code_t
|
||||
@ -557,7 +601,8 @@ grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
|
||||
grub_crypto_hmac_write (hnd, data, datalen);
|
||||
return grub_crypto_hmac_fini (hnd, out);
|
||||
grub_crypto_hmac_fini (hnd, out);
|
||||
return GPG_ERR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -64,7 +64,10 @@ grub_get_weekday_name (struct grub_datetime *datetime)
|
||||
#define SECPERDAY (24*SECPERHOUR)
|
||||
#define DAYSPERYEAR 365
|
||||
#define DAYSPER4YEARS (4*DAYSPERYEAR+1)
|
||||
|
||||
/* 24 leap years in 100 years */
|
||||
#define DAYSPER100YEARS (100 * DAYSPERYEAR + 24)
|
||||
/* 97 leap years in 400 years */
|
||||
#define DAYSPER400YEARS (400 * DAYSPERYEAR + 97)
|
||||
|
||||
void
|
||||
grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
|
||||
@ -76,10 +79,12 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
|
||||
/* Convenience: let's have 3 consecutive non-bissextile years
|
||||
at the beginning of the counting date. So count from 1901. */
|
||||
int days_epoch;
|
||||
/* Number of days since 1st Januar, 1901. */
|
||||
/* Number of days since 1st January, 1 (proleptic). */
|
||||
unsigned days;
|
||||
/* Seconds into current day. */
|
||||
unsigned secs_in_day;
|
||||
/* Tracks whether this is a leap year. */
|
||||
bool bisextile;
|
||||
|
||||
/* Transform C divisions and modulos to mathematical ones */
|
||||
if (nix < 0)
|
||||
@ -92,27 +97,63 @@ grub_unixtime2datetime (grub_int64_t nix, struct grub_datetime *datetime)
|
||||
days_epoch = grub_divmod64 (nix, SECPERDAY, NULL);
|
||||
|
||||
secs_in_day = nix - days_epoch * SECPERDAY;
|
||||
days = days_epoch + 69 * DAYSPERYEAR + 17;
|
||||
/*
|
||||
* 1970 is Unix Epoch. Adjust to a year 1 epoch:
|
||||
* Leap year logic:
|
||||
* - Years evenly divisible by 400 are leap years
|
||||
* - Otherwise, if divisible by 100 are not leap years
|
||||
* - Otherwise, if divisible by 4 are leap years
|
||||
* There are four 400-year periods (1600 years worth of days with leap days)
|
||||
* There are 369 years in addition to the four 400 year periods
|
||||
* There are three 100-year periods worth of leap days (3*24)
|
||||
* There are 17 leap days in 69 years (beyond the three 100 year periods)
|
||||
*/
|
||||
days = 4 * DAYSPER400YEARS + 369 * DAYSPERYEAR + 3 * 24 + 17 + days_epoch;
|
||||
|
||||
datetime->year = 1901 + 4 * (days / DAYSPER4YEARS);
|
||||
datetime->year = 1 + 400 * (days / DAYSPER400YEARS);
|
||||
days %= DAYSPER400YEARS;
|
||||
|
||||
/*
|
||||
* On 31st December of bissextile (leap) years 365 days from the beginning
|
||||
* of the year elapsed but year isn't finished yet - every 400 years
|
||||
* 396 is 4 years less than 400 year leap cycle
|
||||
* 96 is 1 day less than number of leap days in 400 years
|
||||
*/
|
||||
if (days / DAYSPER100YEARS == 4)
|
||||
{
|
||||
datetime->year += 396;
|
||||
days -= 396 * DAYSPERYEAR + 96;
|
||||
}
|
||||
else
|
||||
{
|
||||
datetime->year += 100 * (days / DAYSPER100YEARS);
|
||||
days %= DAYSPER100YEARS;
|
||||
}
|
||||
|
||||
datetime->year += 4 * (days / DAYSPER4YEARS);
|
||||
days %= DAYSPER4YEARS;
|
||||
/* On 31st December of bissextile years 365 days from the beginning
|
||||
of the year elapsed but year isn't finished yet */
|
||||
/*
|
||||
* On 31st December of bissextile (leap) years 365 days from the beginning
|
||||
* of the year elapsed but year isn't finished yet - every 4 years
|
||||
*/
|
||||
if (days / DAYSPERYEAR == 4)
|
||||
{
|
||||
datetime->year += 3;
|
||||
days -= 3*DAYSPERYEAR;
|
||||
days -= 3 * DAYSPERYEAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
datetime->year += days / DAYSPERYEAR;
|
||||
days %= DAYSPERYEAR;
|
||||
}
|
||||
for (i = 0; i < 12
|
||||
&& days >= (i==1 && datetime->year % 4 == 0
|
||||
? 29 : months[i]); i++)
|
||||
days -= (i==1 && datetime->year % 4 == 0
|
||||
? 29 : months[i]);
|
||||
|
||||
bisextile = (datetime->year % 4 == 0
|
||||
&& (datetime->year % 100 != 0
|
||||
|| datetime->year % 400 == 0)) ? true : false;
|
||||
for (i = 0;
|
||||
i < 12 && days >= ((i == 1 && bisextile == true) ? 29 : months[i]);
|
||||
i++)
|
||||
days -= ((i == 1 && bisextile == true) ? 29 : months[i]);
|
||||
datetime->month = i + 1;
|
||||
datetime->day = 1 + days;
|
||||
datetime->hour = (secs_in_day / SECPERHOUR);
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#include <grub/efi/tpm.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
#include <tss2_types.h>
|
||||
#include <tcg2.h>
|
||||
|
||||
static grub_err_t
|
||||
@ -141,3 +142,42 @@ grub_tcg2_submit_command (grub_size_t input_size,
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_tcg2_cap_pcr (grub_uint8_t pcr)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_efi_status_t status;
|
||||
grub_efi_tpm2_protocol_t *protocol;
|
||||
EFI_TCG2_EVENT *event;
|
||||
grub_uint8_t separator[4] = {0};
|
||||
|
||||
if (pcr >= TPM_MAX_PCRS)
|
||||
return GRUB_ERR_BAD_ARGUMENT;
|
||||
|
||||
err = tcg2_get_protocol (&protocol);
|
||||
if (err != GRUB_ERR_NONE)
|
||||
return err;
|
||||
|
||||
event = grub_zalloc (sizeof (EFI_TCG2_EVENT) + sizeof (separator));
|
||||
if (event == NULL)
|
||||
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
|
||||
N_("cannot allocate TPM event buffer"));
|
||||
|
||||
event->Header.HeaderSize = sizeof (EFI_TCG2_EVENT_HEADER);
|
||||
event->Header.HeaderVersion = 1;
|
||||
event->Header.PCRIndex = pcr;
|
||||
event->Header.EventType = GRUB_EV_SEPARATOR;
|
||||
event->Size = sizeof (*event) - sizeof (event->Event) + sizeof (separator);
|
||||
grub_memcpy (event->Event, separator, sizeof (separator));
|
||||
|
||||
status = protocol->hash_log_extend_event (protocol, 0,
|
||||
(grub_addr_t) separator,
|
||||
sizeof (separator), event);
|
||||
grub_free (event);
|
||||
|
||||
if (status != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
- return REG_NOERROR;
|
||||
+ return err;
|
||||
}
|
||||
|
||||
|
||||
/* If it is possible to do searching in single byte encoding instead of UTF-8
|
||||
@@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
|
||||
{
|
||||
@ -106,5 +106,5 @@
|
||||
+
|
||||
+ return err;
|
||||
}
|
||||
|
||||
|
||||
/* Functions for token which are used in the parser. */
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
--- a/lib/regexec.c 2020-10-21 14:25:35.310195912 +0000
|
||||
+++ b/lib/regexec.c 2020-10-21 14:32:07.961765604 +0000
|
||||
@@ -828,7 +828,11 @@
|
||||
@@ -807,7 +807,11 @@
|
||||
break;
|
||||
if (__glibc_unlikely (err != REG_NOMATCH))
|
||||
goto free_return;
|
||||
|
||||
52
grub-core/lib/hwfeatures-gcry.c
Normal file
52
grub-core/lib/hwfeatures-gcry.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
|
||||
#include <grub/hwfeatures-gcry.h>
|
||||
#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
|
||||
#include <grub/x86_64/efi/hwfeatures-gcry.h>
|
||||
#endif
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static bool __gcry_use_hwf = false;
|
||||
|
||||
bool
|
||||
grub_gcry_hwf_enabled (void)
|
||||
{
|
||||
return __gcry_use_hwf;
|
||||
}
|
||||
|
||||
void
|
||||
grub_enable_gcry_hwf (void)
|
||||
{
|
||||
#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
|
||||
grub_enable_gcry_hwf_x86_64_efi ();
|
||||
#endif
|
||||
__gcry_use_hwf = true;
|
||||
}
|
||||
|
||||
void
|
||||
grub_reset_gcry_hwf (void)
|
||||
{
|
||||
#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
|
||||
grub_reset_gcry_hwf_x86_64_efi ();
|
||||
#endif
|
||||
__gcry_use_hwf = false;
|
||||
}
|
||||
@ -26,6 +26,8 @@
|
||||
#include <grub/relocator.h>
|
||||
#include <grub/relocator_private.h>
|
||||
|
||||
#include <grub/i386/memory.h>
|
||||
|
||||
extern grub_uint8_t grub_relocator_forward_start;
|
||||
extern grub_uint8_t grub_relocator_forward_end;
|
||||
extern grub_uint8_t grub_relocator_backward_start;
|
||||
@ -41,20 +43,122 @@ extern grub_size_t grub_relocator_forward_chunk_size;
|
||||
|
||||
#define RELOCATOR_SIZEOF(x) (&grub_relocator##x##_end - &grub_relocator##x##_start)
|
||||
|
||||
grub_size_t grub_relocator_align = 1;
|
||||
grub_size_t grub_relocator_forward_size;
|
||||
grub_size_t grub_relocator_backward_size;
|
||||
grub_size_t grub_relocator_preamble_size = 0;
|
||||
#ifdef __x86_64__
|
||||
grub_size_t grub_relocator_jumper_size = 12;
|
||||
#else
|
||||
grub_size_t grub_relocator_jumper_size = 7;
|
||||
#endif
|
||||
#if defined(__x86_64__) && defined(GRUB_MACHINE_EFI)
|
||||
grub_size_t grub_relocator_align = 4096;
|
||||
#else
|
||||
grub_size_t grub_relocator_align = 1;
|
||||
#endif
|
||||
|
||||
#if defined(__x86_64__) && defined(GRUB_MACHINE_EFI)
|
||||
|
||||
#define PAGE_PRESENT 1
|
||||
#define PAGE_WRITABLE 2
|
||||
#define PAGE_USER 4
|
||||
#define PAGE_PS 0x80
|
||||
#define PAGE_IDX_SIZE 9
|
||||
#define PAGE_PS_SHIFT 21
|
||||
#define PAGE_NUM_ENTRIES 0x200
|
||||
#define PS_PAGE_SIZE 0x200000
|
||||
|
||||
static grub_uint64_t max_ram_size;
|
||||
|
||||
/* Helper for grub_get_multiboot_mmap_count. */
|
||||
static int
|
||||
max_hook (grub_uint64_t addr,
|
||||
grub_uint64_t size,
|
||||
grub_memory_type_t type __attribute__ ((unused)),
|
||||
void *data __attribute__ ((unused)))
|
||||
{
|
||||
max_ram_size = grub_max (max_ram_size, addr + size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_uint64_t
|
||||
find_max_size (void)
|
||||
{
|
||||
if (!max_ram_size)
|
||||
{
|
||||
/* We need to map the first 4GiB of address space as well as all the
|
||||
available RAM, so start with 4GiB and increase if we see any RAM
|
||||
above this. */
|
||||
max_ram_size = 1ULL << 32;
|
||||
|
||||
grub_mmap_iterate (max_hook, NULL);
|
||||
}
|
||||
|
||||
return max_ram_size;
|
||||
}
|
||||
|
||||
void
|
||||
grub_cpu_relocator_preamble (void *rels)
|
||||
{
|
||||
grub_uint64_t nentries = (find_max_size () + PS_PAGE_SIZE - 1) >> PAGE_PS_SHIFT;
|
||||
grub_uint64_t npt2pages = (nentries + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
|
||||
grub_uint64_t npt3pages = (npt2pages + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
|
||||
grub_uint8_t *p = rels;
|
||||
grub_uint64_t *pt4 = (grub_uint64_t *) (p + GRUB_PAGE_SIZE);
|
||||
grub_uint64_t *pt3 = pt4 + PAGE_NUM_ENTRIES;
|
||||
grub_uint64_t *pt2 = pt3 + (npt3pages << PAGE_IDX_SIZE);
|
||||
grub_uint64_t *endpreamble = pt2 + (npt2pages << PAGE_IDX_SIZE);
|
||||
grub_uint64_t i;
|
||||
|
||||
/* movabs $pt4, %rax. */
|
||||
*p++ = 0x48;
|
||||
*p++ = 0xb8;
|
||||
*(grub_uint64_t *) p = (grub_uint64_t) pt4;
|
||||
p += 8;
|
||||
|
||||
/* mov %rax, %cr3. */
|
||||
*p++ = 0x0f;
|
||||
*p++ = 0x22;
|
||||
*p++ = 0xd8;
|
||||
|
||||
/* jmp $endpreamble. */
|
||||
*p++ = 0xe9;
|
||||
*(grub_uint32_t *) p = (grub_uint8_t *) endpreamble - p - 4;
|
||||
|
||||
for (i = 0; i < npt3pages; i++)
|
||||
pt4[i] = ((grub_uint64_t) pt3 + (i << GRUB_PAGE_SHIFT)) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
|
||||
for (i = 0; i < npt2pages; i++)
|
||||
pt3[i] = ((grub_uint64_t) pt2 + (i << GRUB_PAGE_SHIFT)) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
|
||||
for (i = 0; i < (npt2pages << PAGE_IDX_SIZE); i++)
|
||||
pt2[i] = (i << PAGE_PS_SHIFT) | PAGE_PS | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
|
||||
}
|
||||
|
||||
static void
|
||||
compute_preamble_size (void)
|
||||
{
|
||||
grub_uint64_t nentries = (find_max_size () + PS_PAGE_SIZE - 1) >> PAGE_PS_SHIFT;
|
||||
grub_uint64_t npt2pages = (nentries + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
|
||||
grub_uint64_t npt3pages = (npt2pages + PAGE_NUM_ENTRIES - 1) >> PAGE_IDX_SIZE;
|
||||
grub_relocator_preamble_size = (npt2pages + npt3pages + 1 + 1) << GRUB_PAGE_SHIFT;
|
||||
}
|
||||
|
||||
#else
|
||||
void
|
||||
grub_cpu_relocator_preamble (void *rels __attribute__((unused)))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
grub_cpu_relocator_init (void)
|
||||
{
|
||||
grub_relocator_forward_size = RELOCATOR_SIZEOF (_forward);
|
||||
grub_relocator_backward_size = RELOCATOR_SIZEOF (_backward);
|
||||
#if defined(__x86_64__) && defined(GRUB_MACHINE_EFI)
|
||||
compute_preamble_size ();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@ -56,6 +56,52 @@ grub_ieee1275_tpm_init (void)
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_ieee1275_ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
|
||||
grub_uint32_t eventtype,
|
||||
const char *description,
|
||||
grub_size_t description_size,
|
||||
void *buf, grub_size_t size)
|
||||
{
|
||||
struct tpm_2hash_ext_log
|
||||
{
|
||||
struct grub_ieee1275_common_hdr common;
|
||||
grub_ieee1275_cell_t method;
|
||||
grub_ieee1275_cell_t ihandle;
|
||||
grub_ieee1275_cell_t size;
|
||||
grub_ieee1275_cell_t buf;
|
||||
grub_ieee1275_cell_t description_size;
|
||||
grub_ieee1275_cell_t description;
|
||||
grub_ieee1275_cell_t eventtype;
|
||||
grub_ieee1275_cell_t pcrindex;
|
||||
grub_ieee1275_cell_t catch_result;
|
||||
grub_ieee1275_cell_t rc;
|
||||
};
|
||||
struct tpm_2hash_ext_log args;
|
||||
|
||||
INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
|
||||
args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
|
||||
args.ihandle = grub_ieee1275_tpm_ihandle;
|
||||
args.pcrindex = pcrindex;
|
||||
args.eventtype = eventtype;
|
||||
args.description = (grub_ieee1275_cell_t) description;
|
||||
args.description_size = description_size;
|
||||
args.buf = (grub_ieee1275_cell_t) buf;
|
||||
args.size = (grub_ieee1275_cell_t) size;
|
||||
|
||||
if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
|
||||
|
||||
/*
|
||||
* catch_result is set if firmware does not support 2hash-ext-log
|
||||
* rc is GRUB_IEEE1275_CELL_FALSE (0) on failure
|
||||
*/
|
||||
if ((args.catch_result) || args.rc == GRUB_IEEE1275_CELL_FALSE)
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, "2HASH-EXT-LOG failed: Firmware is likely too old.\n");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_tcg2_get_max_output_size (grub_size_t *size)
|
||||
{
|
||||
@ -155,3 +201,22 @@ grub_tcg2_submit_command (grub_size_t input_size,
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_tcg2_cap_pcr (grub_uint8_t pcr)
|
||||
{
|
||||
char separator[4] = {0};
|
||||
static int error_displayed = 0;
|
||||
grub_err_t err;
|
||||
|
||||
err = grub_ieee1275_ibmvtpm_2hash_ext_log (pcr, GRUB_EV_SEPARATOR,
|
||||
separator, sizeof (separator),
|
||||
separator, sizeof (separator));
|
||||
if (err != GRUB_ERR_NONE && !error_displayed)
|
||||
{
|
||||
error_displayed++;
|
||||
return err;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
@ -508,6 +508,9 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix)
|
||||
char *ret;
|
||||
int len = grub_strlen (buf);
|
||||
ret = grub_malloc (len + 2);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
grub_memcpy (ret, buf, len);
|
||||
if (len && ret[len - 1] == '\n')
|
||||
ret[len] = 0;
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
From 42e9975171439e2e9713e122cb0e74174f057e98 Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Mon, 25 Aug 2025 15:54:24 +0800
|
||||
Subject: [PATCH 1/4] libgcrypt/kdf: Implement blake2b_512.hash_buffers()
|
||||
|
||||
Add argon2_blake2b_512_hash_buffers() as the replacement of
|
||||
_gcry_digest_spec_blake2b_512.hash_buffers().
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 25 ++++++++++++++++++++++-
|
||||
1 file changed, 24 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
index 0689f88b1..08e3ef658 100644
|
||||
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
@@ -129,10 +129,31 @@ beswap64_block (u64 *dst)
|
||||
#endif
|
||||
}
|
||||
|
||||
+/* Implementation of _gcry_blake2b_512_hash_buffers */
|
||||
+static gcry_err_code_t
|
||||
+argon2_blake2b_512_hash_buffers (void *outbuf, const gcry_buffer_t *iov, int iovcnt)
|
||||
+{
|
||||
+ void *hd;
|
||||
+
|
||||
+ hd = xtrymalloc (_gcry_digest_spec_blake2b_512.contextsize);
|
||||
+ if (!hd)
|
||||
+ return GPG_ERR_OUT_OF_MEMORY;
|
||||
+
|
||||
+ _gcry_digest_spec_blake2b_512.init (hd, 0);
|
||||
+ for (;iovcnt > 0; iov++, iovcnt--)
|
||||
+ _gcry_digest_spec_blake2b_512.write (hd, (const char*)iov[0].data + iov[0].off, iov[0].len);
|
||||
+ _gcry_digest_spec_blake2b_512.final (hd);
|
||||
+ grub_memcpy (outbuf, _gcry_digest_spec_blake2b_512.read (hd), 512 / 8);
|
||||
+
|
||||
+ xfree (hd);
|
||||
+
|
||||
+ return GPG_ERR_NO_ERROR;
|
||||
+}
|
||||
|
||||
static gpg_err_code_t
|
||||
argon2_fill_first_blocks (argon2_ctx_t a)
|
||||
{
|
||||
+ gpg_err_code_t err;
|
||||
unsigned char h0_01_i[72];
|
||||
unsigned char buf[10][4];
|
||||
gcry_buffer_t iov[8];
|
||||
@@ -195,7 +216,9 @@ argon2_fill_first_blocks (argon2_ctx_t a)
|
||||
iov_count++;
|
||||
}
|
||||
|
||||
- _gcry_digest_spec_blake2b_512.hash_buffers (h0_01_i, 64, iov, iov_count);
|
||||
+ err = argon2_blake2b_512_hash_buffers (h0_01_i, iov, iov_count);
|
||||
+ if (err != GPG_ERR_NO_ERROR)
|
||||
+ return err;
|
||||
|
||||
for (i = 0; i < a->lanes; i++)
|
||||
{
|
||||
--
|
||||
2.51.0
|
||||
|
||||
48
grub-core/lib/libgcrypt-patches/10-kdf-use-GPG-errs.patch
Normal file
48
grub-core/lib/libgcrypt-patches/10-kdf-use-GPG-errs.patch
Normal file
@ -0,0 +1,48 @@
|
||||
From 89f793515d927d8f7099b61d0b7b200611e56acd Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Mon, 25 Aug 2025 15:56:03 +0800
|
||||
Subject: [PATCH 2/4] libgcrypt/kdf: Get rid of gpg_err_code_from_errno()
|
||||
|
||||
gpg_err_code_from_errno() requires libgcrypt_wrap/mem.c which is not in
|
||||
Makefile.utilgcry.def. This commit replaces gpg_err_code_from_errno()
|
||||
with GPG_ERR_* to avoid the build errors.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
index 08e3ef658..6e0351d8a 100644
|
||||
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
@@ -265,7 +265,7 @@ argon2_init (argon2_ctx_t a, unsigned int parallelism,
|
||||
block = xtrymalloc (1024 * memory_blocks);
|
||||
if (!block)
|
||||
{
|
||||
- ec = gpg_err_code_from_errno (errno);
|
||||
+ ec = GPG_ERR_OUT_OF_MEMORY;
|
||||
return ec;
|
||||
}
|
||||
memset (block, 0, 1024 * memory_blocks);
|
||||
@@ -273,7 +273,7 @@ argon2_init (argon2_ctx_t a, unsigned int parallelism,
|
||||
thread_data = xtrymalloc (a->lanes * sizeof (struct argon2_thread_data));
|
||||
if (!thread_data)
|
||||
{
|
||||
- ec = gpg_err_code_from_errno (errno);
|
||||
+ ec = GPG_ERR_OUT_OF_MEMORY;
|
||||
xfree (block);
|
||||
return ec;
|
||||
}
|
||||
@@ -624,7 +624,7 @@ argon2_open (gcry_kdf_hd_t *hd, int subalgo,
|
||||
n = offsetof (struct argon2_context, out) + taglen;
|
||||
a = xtrymalloc (n);
|
||||
if (!a)
|
||||
- return gpg_err_code_from_errno (errno);
|
||||
+ return GPG_ERR_OUT_OF_MEMORY;
|
||||
|
||||
a->algo = GCRY_KDF_ARGON2;
|
||||
a->hash_type = hash_type;
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@ -0,0 +1,166 @@
|
||||
From fc9c57f54fd28685f7df79e53078e1dc9e44f964 Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Mon, 25 Aug 2025 16:00:17 +0800
|
||||
Subject: [PATCH 3/4] libgcrypt/kdf: Remove unsupported KDFs
|
||||
|
||||
Clean up _gcry_kdf_*() to remove unsupported KDFs.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 119 ----------------------
|
||||
1 file changed, 119 deletions(-)
|
||||
|
||||
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
index 6e0351d8a..c51a70eff 100644
|
||||
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
@@ -821,64 +821,6 @@ _gcry_kdf_open (gcry_kdf_hd_t *hd, int algo, int subalgo,
|
||||
key, keylen, ad, adlen);
|
||||
break;
|
||||
|
||||
- case GCRY_KDF_BALLOON:
|
||||
- if (!inputlen || !saltlen || keylen || adlen)
|
||||
- ec = GPG_ERR_INV_VALUE;
|
||||
- else
|
||||
- {
|
||||
- (void)key;
|
||||
- (void)ad;
|
||||
- ec = balloon_open (hd, subalgo, param, paramlen,
|
||||
- input, inputlen, salt, saltlen);
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF:
|
||||
- if (!inputlen || !paramlen || !adlen)
|
||||
- ec = GPG_ERR_INV_VALUE;
|
||||
- else
|
||||
- {
|
||||
- (void)salt;
|
||||
- (void)key;
|
||||
- ec = onestep_kdf_open (hd, subalgo, param, paramlen,
|
||||
- input, inputlen, ad, adlen);
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF_MAC:
|
||||
- if (!inputlen || !paramlen || !keylen || !adlen)
|
||||
- ec = GPG_ERR_INV_VALUE;
|
||||
- else
|
||||
- {
|
||||
- (void)salt;
|
||||
- ec = onestep_kdf_mac_open (hd, subalgo, param, paramlen,
|
||||
- input, inputlen, key, keylen, ad, adlen);
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_HKDF:
|
||||
- if (!inputlen || !paramlen)
|
||||
- ec = GPG_ERR_INV_VALUE;
|
||||
- else
|
||||
- {
|
||||
- (void)salt;
|
||||
- ec = hkdf_open (hd, subalgo, param, paramlen,
|
||||
- input, inputlen, key, keylen, ad, adlen);
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_X963_KDF:
|
||||
- if (!inputlen || !paramlen)
|
||||
- ec = GPG_ERR_INV_VALUE;
|
||||
- else
|
||||
- {
|
||||
- (void)salt;
|
||||
- (void)key;
|
||||
- ec = x963_kdf_open (hd, subalgo, param, paramlen,
|
||||
- input, inputlen, ad, adlen);
|
||||
- }
|
||||
- break;
|
||||
-
|
||||
default:
|
||||
ec = GPG_ERR_UNKNOWN_ALGORITHM;
|
||||
break;
|
||||
@@ -898,26 +840,6 @@ _gcry_kdf_compute (gcry_kdf_hd_t h, const struct gcry_kdf_thread_ops *ops)
|
||||
ec = argon2_compute ((argon2_ctx_t)(void *)h, ops);
|
||||
break;
|
||||
|
||||
- case GCRY_KDF_BALLOON:
|
||||
- ec = balloon_compute_all ((balloon_ctx_t)(void *)h, ops);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF:
|
||||
- ec = onestep_kdf_compute ((onestep_kdf_ctx_t)(void *)h, ops);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF_MAC:
|
||||
- ec = onestep_kdf_mac_compute ((onestep_kdf_mac_ctx_t)(void *)h, ops);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_HKDF:
|
||||
- ec = hkdf_compute ((hkdf_ctx_t)(void *)h, ops);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_X963_KDF:
|
||||
- ec = x963_kdf_compute ((x963_kdf_ctx_t)(void *)h, ops);
|
||||
- break;
|
||||
-
|
||||
default:
|
||||
ec = GPG_ERR_UNKNOWN_ALGORITHM;
|
||||
break;
|
||||
@@ -938,27 +860,6 @@ _gcry_kdf_final (gcry_kdf_hd_t h, size_t resultlen, void *result)
|
||||
ec = argon2_final ((argon2_ctx_t)(void *)h, resultlen, result);
|
||||
break;
|
||||
|
||||
- case GCRY_KDF_BALLOON:
|
||||
- ec = balloon_final ((balloon_ctx_t)(void *)h, resultlen, result);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF:
|
||||
- ec = onestep_kdf_final ((onestep_kdf_ctx_t)(void *)h, resultlen, result);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF_MAC:
|
||||
- ec = onestep_kdf_mac_final ((onestep_kdf_mac_ctx_t)(void *)h,
|
||||
- resultlen, result);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_HKDF:
|
||||
- ec = hkdf_final ((hkdf_ctx_t)(void *)h, resultlen, result);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_X963_KDF:
|
||||
- ec = x963_kdf_final ((x963_kdf_ctx_t)(void *)h, resultlen, result);
|
||||
- break;
|
||||
-
|
||||
default:
|
||||
ec = GPG_ERR_UNKNOWN_ALGORITHM;
|
||||
break;
|
||||
@@ -976,26 +877,6 @@ _gcry_kdf_close (gcry_kdf_hd_t h)
|
||||
argon2_close ((argon2_ctx_t)(void *)h);
|
||||
break;
|
||||
|
||||
- case GCRY_KDF_BALLOON:
|
||||
- balloon_close ((balloon_ctx_t)(void *)h);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF:
|
||||
- onestep_kdf_close ((onestep_kdf_ctx_t)(void *)h);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_ONESTEP_KDF_MAC:
|
||||
- onestep_kdf_mac_close ((onestep_kdf_mac_ctx_t)(void *)h);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_HKDF:
|
||||
- hkdf_close ((hkdf_ctx_t)(void *)h);
|
||||
- break;
|
||||
-
|
||||
- case GCRY_KDF_X963_KDF:
|
||||
- x963_kdf_close ((x963_kdf_ctx_t)(void *)h);
|
||||
- break;
|
||||
-
|
||||
default:
|
||||
break;
|
||||
}
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
From 990a5f7df076200aa031b1bcde6bc4b13d4f198e Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Mon, 25 Aug 2025 16:01:45 +0800
|
||||
Subject: [PATCH 4/4] libgcrypt/kdf: Fix 64-bit modulus on 32-bit platforms
|
||||
|
||||
Use grub_divmod64() for the 64-bit modulus to prevent creation of
|
||||
special division calls such as __umoddi3() and __aeabi_uldivmod() on
|
||||
32-bit platforms.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/lib/libgcrypt-grub/cipher/kdf.c | 16 ++++++++++++----
|
||||
1 file changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/grub-core/lib/libgcrypt-grub/cipher/kdf.c b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
index c51a70eff..f4bb51809 100644
|
||||
--- a/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
+++ b/grub-core/lib/libgcrypt-grub/cipher/kdf.c
|
||||
@@ -375,6 +375,7 @@ index_alpha (argon2_ctx_t a, const struct argon2_thread_data *t,
|
||||
u32 reference_area_size;
|
||||
u64 relative_position;
|
||||
u32 start_position;
|
||||
+ u64 remainder;
|
||||
|
||||
if (t->pass == 0)
|
||||
{
|
||||
@@ -411,7 +412,8 @@ index_alpha (argon2_ctx_t a, const struct argon2_thread_data *t,
|
||||
? 0
|
||||
: (t->slice + 1) * a->segment_length;
|
||||
|
||||
- return (start_position + relative_position) % a->lane_length;
|
||||
+ grub_divmod64 (start_position + relative_position, a->lane_length, &remainder);
|
||||
+ return remainder;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -425,6 +427,7 @@ argon2_compute_segment (void *priv)
|
||||
u64 input_block[1024/sizeof (u64)];
|
||||
u64 address_block[1024/sizeof (u64)];
|
||||
u64 *random_block = NULL;
|
||||
+ u64 remainder;
|
||||
|
||||
if (a->hash_type == GCRY_KDF_ARGON2I
|
||||
|| (a->hash_type == GCRY_KDF_ARGON2ID && t->pass == 0 && t->slice < 2))
|
||||
@@ -449,7 +452,8 @@ argon2_compute_segment (void *priv)
|
||||
i = 0;
|
||||
|
||||
curr_offset = t->lane * a->lane_length + t->slice * a->segment_length + i;
|
||||
- if ((curr_offset % a->lane_length))
|
||||
+ grub_divmod64 (curr_offset, a->lane_length, &remainder);
|
||||
+ if (remainder)
|
||||
prev_offset = curr_offset - 1;
|
||||
else
|
||||
prev_offset = curr_offset + a->lane_length - 1;
|
||||
@@ -459,7 +463,8 @@ argon2_compute_segment (void *priv)
|
||||
u64 *ref_block, *curr_block;
|
||||
u64 rand64;
|
||||
|
||||
- if ((curr_offset % a->lane_length) == 1)
|
||||
+ grub_divmod64 (curr_offset, a->lane_length, &remainder);
|
||||
+ if (remainder == 1)
|
||||
prev_offset = curr_offset - 1;
|
||||
|
||||
if (random_block)
|
||||
@@ -475,7 +480,10 @@ argon2_compute_segment (void *priv)
|
||||
if (t->pass == 0 && t->slice == 0)
|
||||
ref_lane = t->lane;
|
||||
else
|
||||
- ref_lane = (rand64 >> 32) % a->lanes;
|
||||
+ {
|
||||
+ grub_divmod64 (rand64 >> 32, a->lanes, &remainder);
|
||||
+ ref_lane = remainder;
|
||||
+ }
|
||||
|
||||
ref_index = index_alpha (a, t, i, (rand64 & 0xffffffff),
|
||||
ref_lane == t->lane);
|
||||
--
|
||||
2.51.0
|
||||
|
||||
87
grub-core/lib/libgcrypt-patches/13_add_hwfeatures.patch
Normal file
87
grub-core/lib/libgcrypt-patches/13_add_hwfeatures.patch
Normal file
@ -0,0 +1,87 @@
|
||||
From 4403c452240417aaac7d3120c80b1325b7218768 Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Fri, 18 Jul 2025 15:21:51 +0800
|
||||
Subject: [PATCH 1/4] libgcrypt: Implement _gcry_get_hw_features()
|
||||
|
||||
Implement _gcry_get_hw_features() and enable hardware feature detection
|
||||
for x86_64.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/Makefile.gcry.def | 8 ++++
|
||||
grub-core/lib/libgcrypt-grub/src/hwfeatures.c | 47 +++++++++++++++++++
|
||||
2 files changed, 55 insertions(+)
|
||||
create mode 100644 grub-core/lib/libgcrypt-grub/src/hwfeatures.c
|
||||
|
||||
diff --git a/grub-core/Makefile.gcry.def b/grub-core/Makefile.gcry.def
|
||||
index a0593fa09..c8caf17dc 100644
|
||||
--- a/grub-core/Makefile.gcry.def
|
||||
+++ b/grub-core/Makefile.gcry.def
|
||||
@@ -226,3 +226,11 @@ module = {
|
||||
cppflags = '$(CPPFLAGS_GCRY)';
|
||||
};
|
||||
|
||||
+module = {
|
||||
+ name = gcry_hwfeatures;
|
||||
+ common = lib/libgcrypt-grub/src/hwfeatures.c;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/src/hwf-x86.c;
|
||||
+
|
||||
+ cflags = '$(CFLAGS_GCRY)';
|
||||
+ cppflags = '$(CPPFLAGS_GCRY) $(CPPFLAGS_GCRY_ASM)';
|
||||
+};
|
||||
diff --git a/grub-core/lib/libgcrypt-grub/src/hwfeatures.c b/grub-core/lib/libgcrypt-grub/src/hwfeatures.c
|
||||
new file mode 100644
|
||||
index 000000000..4d744f8ec
|
||||
--- /dev/null
|
||||
+++ b/grub-core/lib/libgcrypt-grub/src/hwfeatures.c
|
||||
@@ -0,0 +1,47 @@
|
||||
+/*
|
||||
+ * GRUB -- GRand Unified Bootloader
|
||||
+ * Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
+ *
|
||||
+ * GRUB is free software: you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation, either version 3 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <grub/dl.h>
|
||||
+GRUB_MOD_LICENSE ("GPLv3+");
|
||||
+
|
||||
+#include <grub/crypto.h>
|
||||
+#include <grub/hwfeatures-gcry.h>
|
||||
+#include "hwf-common.h"
|
||||
+
|
||||
+unsigned int
|
||||
+_gcry_get_hw_features (void)
|
||||
+{
|
||||
+ static bool detected = false;
|
||||
+ static unsigned int hw_features = 0;
|
||||
+
|
||||
+ if (grub_gcry_hwf_enabled () == false)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (detected == true)
|
||||
+ return hw_features;
|
||||
+
|
||||
+#if defined (__x86_64__) && defined (GRUB_MACHINE_EFI)
|
||||
+ hw_features = _gcry_hwf_detect_x86 ();
|
||||
+#endif
|
||||
+
|
||||
+ grub_dprintf ("hwfeatures", "Detected features: 0x%x\n", hw_features);
|
||||
+
|
||||
+ detected = true;
|
||||
+
|
||||
+ return hw_features;
|
||||
+}
|
||||
--
|
||||
2.51.0
|
||||
|
||||
35
grub-core/lib/libgcrypt-patches/14_fix_build_shaext.patch
Normal file
35
grub-core/lib/libgcrypt-patches/14_fix_build_shaext.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From 5698f7c5055ea481d0040ea4495829e5d02781cc Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Fri, 18 Jul 2025 15:34:21 +0800
|
||||
Subject: [PATCH 2/4] libgcrypt: Declare the sha256 shaext function
|
||||
|
||||
There is no prototype of _gcry_sha256_transform_intel_shaext() defined
|
||||
in the header or libgcrypt-grub/cipher/sha256.c, and gcc may complain
|
||||
the missing-prototypes error when compiling sha256-intel-shaext.c.
|
||||
|
||||
Declare the prototype in sha256-intel-shaext.c to avoid the error.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c b/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c
|
||||
index 48c09eefe..7ec49f05e 100644
|
||||
--- a/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c
|
||||
+++ b/grub-core/lib/libgcrypt-grub/cipher/sha256-intel-shaext.c
|
||||
@@ -95,6 +95,11 @@ typedef struct u128_s
|
||||
u32 a, b, c, d;
|
||||
} u128_t;
|
||||
|
||||
+
|
||||
+unsigned int ASM_FUNC_ATTR
|
||||
+_gcry_sha256_transform_intel_shaext(u32 state[8], const unsigned char *data,
|
||||
+ size_t nblks);
|
||||
+
|
||||
/*
|
||||
* Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
|
||||
*/
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
From 3443b213bb87112144d753678d0f1bbbc72b2b7a Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Fri, 18 Jul 2025 15:23:25 +0800
|
||||
Subject: [PATCH 3/4] libgcrypt: Add hardware acceleration for gcry_sha256
|
||||
|
||||
Enable hardware acceleration for the gcry_sha256 module when building
|
||||
for the x86_64 EFI target.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/Makefile.gcry.def | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/grub-core/Makefile.gcry.def b/grub-core/Makefile.gcry.def
|
||||
index c8caf17dc..ac1d9a088 100644
|
||||
--- a/grub-core/Makefile.gcry.def
|
||||
+++ b/grub-core/Makefile.gcry.def
|
||||
@@ -17,6 +17,7 @@ module = {
|
||||
module = {
|
||||
name = gcry_blake2;
|
||||
common = lib/libgcrypt-grub/cipher/blake2.c;
|
||||
+
|
||||
cflags = '$(CFLAGS_GCRY)';
|
||||
cppflags = '$(CPPFLAGS_GCRY)';
|
||||
};
|
||||
@@ -172,8 +173,13 @@ module = {
|
||||
module = {
|
||||
name = gcry_sha256;
|
||||
common = lib/libgcrypt-grub/cipher/sha256.c;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-ssse3-amd64.S;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-avx-amd64.S;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-avx2-bmi2-amd64.S;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha256-intel-shaext.c;
|
||||
+
|
||||
cflags = '$(CFLAGS_GCRY) -Wno-cast-align';
|
||||
- cppflags = '$(CPPFLAGS_GCRY)';
|
||||
+ cppflags = '$(CPPFLAGS_GCRY) -DUSE_SHA256 $(CPPFLAGS_GCRY_ASM)';
|
||||
};
|
||||
|
||||
module = {
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
From f62c2c7565237bbf059220e90d3f1f8c8d6eebd5 Mon Sep 17 00:00:00 2001
|
||||
From: Gary Lin <glin@suse.com>
|
||||
Date: Wed, 3 Sep 2025 16:26:55 +0800
|
||||
Subject: [PATCH 4/4] libgcrypt: Add hardware acceleration for gcry_sha512
|
||||
|
||||
Enable hardware acceleration for the gcry_sha512 module when building
|
||||
for the x86_64 EFI target.
|
||||
|
||||
Signed-off-by: Gary Lin <glin@suse.com>
|
||||
---
|
||||
grub-core/Makefile.gcry.def | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/grub-core/Makefile.gcry.def b/grub-core/Makefile.gcry.def
|
||||
index ac1d9a088..64ea5ee24 100644
|
||||
--- a/grub-core/Makefile.gcry.def
|
||||
+++ b/grub-core/Makefile.gcry.def
|
||||
@@ -186,8 +186,13 @@ module = {
|
||||
name = gcry_sha512;
|
||||
common = lib/libgcrypt-grub/cipher/sha512.c;
|
||||
common = lib/libgcrypt-grub/cipher/hash-common.c;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-ssse3-amd64.S;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-avx-amd64.S;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-avx2-bmi2-amd64.S;
|
||||
+ x86_64_efi = lib/libgcrypt-grub/cipher/sha512-avx512-amd64.S;
|
||||
+
|
||||
cflags = '$(CFLAGS_GCRY) -Wno-cast-align';
|
||||
- cppflags = '$(CPPFLAGS_GCRY)';
|
||||
+ cppflags = '$(CPPFLAGS_GCRY) -DUSE_SHA512 $(CPPFLAGS_GCRY_ASM)';
|
||||
};
|
||||
|
||||
module = {
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@ -45,6 +45,7 @@ grub_size_t grub_relocator_align = sizeof (grub_uint32_t);
|
||||
grub_size_t grub_relocator_forward_size;
|
||||
grub_size_t grub_relocator_backward_size;
|
||||
grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF;
|
||||
grub_size_t grub_relocator_preamble_size = 0;
|
||||
|
||||
void
|
||||
grub_cpu_relocator_init (void)
|
||||
@ -53,6 +54,11 @@ grub_cpu_relocator_init (void)
|
||||
grub_relocator_backward_size = RELOCATOR_SIZEOF(backward);
|
||||
}
|
||||
|
||||
void
|
||||
grub_cpu_relocator_preamble (void *rels __attribute__ ((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
write_reg (int regn, grub_uint32_t val, void **target)
|
||||
{
|
||||
|
||||
@ -39,6 +39,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
|
||||
unsigned int c,
|
||||
grub_uint8_t *DK, grub_size_t dkLen)
|
||||
{
|
||||
struct grub_crypto_hmac_handle *hnd = NULL;
|
||||
unsigned int hLen = md->mdlen;
|
||||
grub_uint8_t U[GRUB_CRYPTO_MAX_MDLEN];
|
||||
grub_uint8_t T[GRUB_CRYPTO_MAX_MDLEN];
|
||||
@ -47,7 +48,6 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
|
||||
unsigned int r;
|
||||
unsigned int i;
|
||||
unsigned int k;
|
||||
gcry_err_code_t rc;
|
||||
grub_uint8_t *tmp;
|
||||
grub_size_t tmplen = Slen + 4;
|
||||
|
||||
@ -72,6 +72,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
|
||||
|
||||
grub_memcpy (tmp, S, Slen);
|
||||
|
||||
hnd = grub_crypto_hmac_init (md, P, Plen);
|
||||
if (hnd == NULL)
|
||||
{
|
||||
grub_free (tmp);
|
||||
return GPG_ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (i = 1; i - 1 < l; i++)
|
||||
{
|
||||
grub_memset (T, 0, hLen);
|
||||
@ -85,16 +92,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
|
||||
tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
|
||||
tmp[Slen + 3] = (i & 0x000000ff) >> 0;
|
||||
|
||||
rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U);
|
||||
grub_crypto_hmac_write (hnd, tmp, tmplen);
|
||||
}
|
||||
else
|
||||
rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U);
|
||||
grub_crypto_hmac_write (hnd, U, hLen);
|
||||
|
||||
if (rc != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
grub_free (tmp);
|
||||
return rc;
|
||||
}
|
||||
grub_crypto_hmac_final (hnd, U);
|
||||
grub_crypto_hmac_reset (hnd);
|
||||
|
||||
for (k = 0; k < hLen; k++)
|
||||
T[k] ^= U[k];
|
||||
@ -103,6 +107,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
|
||||
grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
|
||||
}
|
||||
|
||||
grub_crypto_hmac_free (hnd);
|
||||
grub_free (tmp);
|
||||
|
||||
return GPG_ERR_NO_ERROR;
|
||||
|
||||
@ -43,6 +43,7 @@ grub_size_t grub_relocator_align = sizeof (grub_uint32_t);
|
||||
grub_size_t grub_relocator_forward_size;
|
||||
grub_size_t grub_relocator_backward_size;
|
||||
grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF;
|
||||
grub_size_t grub_relocator_preamble_size = 0;
|
||||
|
||||
void
|
||||
grub_cpu_relocator_init (void)
|
||||
@ -51,6 +52,11 @@ grub_cpu_relocator_init (void)
|
||||
grub_relocator_backward_size = RELOCATOR_SIZEOF(backward);
|
||||
}
|
||||
|
||||
void
|
||||
grub_cpu_relocator_preamble (void *rels __attribute__((unused)))
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
write_reg (int regn, grub_uint32_t val, void **target)
|
||||
{
|
||||
|
||||
@ -110,7 +110,7 @@ grub_relocator_new (void)
|
||||
return NULL;
|
||||
|
||||
ret->postchunks = ~(grub_phys_addr_t) 0;
|
||||
ret->relocators_size = grub_relocator_jumper_size;
|
||||
ret->relocators_size = grub_relocator_jumper_size + grub_relocator_preamble_size;
|
||||
grub_dprintf ("relocator", "relocators_size=%lu\n",
|
||||
(unsigned long) ret->relocators_size);
|
||||
return ret;
|
||||
@ -398,9 +398,9 @@ free_subchunk (const struct grub_relocator_subchunk *subchu)
|
||||
if (subchu->post)
|
||||
{
|
||||
int off = subchu->start + subchu->size - fend;
|
||||
grub_memset (subchu->pre->freebytes,
|
||||
0xff, sizeof (subchu->pre->freebytes) - off / 8);
|
||||
subchu->pre->freebytes[off / 8] |= ((1 << (8 - (off % 8))) - 1);
|
||||
grub_memset (subchu->post->freebytes,
|
||||
0xff, sizeof (subchu->post->freebytes) - off / 8 - 1);
|
||||
subchu->post->freebytes[sizeof (subchu->post->freebytes) - off / 8 - 1] |= ((1 << (8 - (off % 8))) - 1);
|
||||
check_leftover (subchu->post);
|
||||
}
|
||||
#endif
|
||||
@ -1605,6 +1605,9 @@ grub_relocator_prepare_relocs (struct grub_relocator *rel, grub_addr_t addr,
|
||||
grub_free (to);
|
||||
}
|
||||
|
||||
grub_cpu_relocator_preamble (rels);
|
||||
rels += grub_relocator_preamble_size;
|
||||
|
||||
for (j = 0; j < nchunks; j++)
|
||||
{
|
||||
grub_dprintf ("relocator", "sorted chunk %p->%p, 0x%lx\n",
|
||||
|
||||
@ -23,6 +23,8 @@
|
||||
#include <grub/err.h>
|
||||
#include <grub/types.h>
|
||||
|
||||
#define GRUB_EV_SEPARATOR 0x04
|
||||
|
||||
extern grub_err_t
|
||||
grub_tcg2_get_max_output_size (grub_size_t *size);
|
||||
|
||||
@ -32,4 +34,7 @@ grub_tcg2_submit_command (grub_size_t input_size,
|
||||
grub_size_t output_size,
|
||||
grub_uint8_t *output);
|
||||
|
||||
extern grub_err_t
|
||||
grub_tcg2_cap_pcr (grub_uint8_t pcr);
|
||||
|
||||
#endif /* ! GRUB_TPM2_TCG2_HEADER */
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
|
||||
#include <tss2_buffer.h>
|
||||
#include <tss2_structs.h>
|
||||
#include <tpm2_cmd.h>
|
||||
#include <tcg2.h>
|
||||
|
||||
grub_err_t
|
||||
@ -47,3 +48,22 @@ grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_tcg2_cap_pcr (grub_uint8_t pcr)
|
||||
{
|
||||
TPMS_AUTH_COMMAND_t authCmd = {
|
||||
.sessionHandle = TPM_RS_PW,
|
||||
};
|
||||
TPM2B_EVENT_t data = {
|
||||
.size = 4,
|
||||
};
|
||||
TPM_RC_t rc;
|
||||
|
||||
/* Submit an EV_SEPARATOR event, i.e. an event with 4 zero-bytes */
|
||||
rc = grub_tpm2_pcr_event (pcr, &authCmd, &data, NULL, NULL);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot cap PCR %u"), pcr);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
@ -89,6 +89,7 @@ tpm2_submit_command (const TPMI_ST_COMMAND_TAG_t tag,
|
||||
|
||||
/* Catch TPM_RC_RETRY and send the command again */
|
||||
do {
|
||||
grub_tpm2_buffer_init (out);
|
||||
err = tpm2_submit_command_real (tag, commandCode, responseCode, in, out);
|
||||
if (*responseCode != TPM_RC_RETRY)
|
||||
break;
|
||||
@ -167,7 +168,6 @@ grub_tpm2_createprimary (const TPMI_RH_HIERARCHY_t primaryHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_CreatePrimary, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -250,7 +250,6 @@ grub_tpm2_startauthsession (const TPMI_DH_OBJECT_t tpmKey,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_StartAuthSession, &responseCode,
|
||||
&in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
@ -308,7 +307,6 @@ grub_tpm2_policypcr (const TPMI_SH_POLICY_t policySessions,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_PolicyPCR, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -347,7 +345,6 @@ grub_tpm2_readpublic (const TPMI_DH_OBJECT_t objectHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_ReadPublic, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -408,7 +405,6 @@ grub_tpm2_load (const TPMI_DH_OBJECT_t parent_handle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_Load, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -475,7 +471,6 @@ grub_tpm2_loadexternal (const TPMS_AUTH_COMMAND_t *authCommand,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_LoadExternal, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -527,7 +522,6 @@ grub_tpm2_unseal (const TPMI_DH_OBJECT_t itemHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_Unseal, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -561,7 +555,6 @@ grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (TPM_ST_NO_SESSIONS, TPM_CC_FlushContext, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -575,6 +568,56 @@ grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
||||
TPM_RC_t
|
||||
grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
|
||||
const TPMS_AUTH_COMMAND_t *authCommand,
|
||||
const TPM2B_EVENT_t *eventData,
|
||||
TPML_DIGEST_VALUES_t *digests,
|
||||
TPMS_AUTH_RESPONSE_t *authResponse)
|
||||
{
|
||||
TPM_RC_t rc;
|
||||
struct grub_tpm2_buffer in;
|
||||
struct grub_tpm2_buffer out;
|
||||
TPML_DIGEST_VALUES_t digestsTmp;
|
||||
TPMS_AUTH_RESPONSE_t authResponseTmp;
|
||||
TPM_RC_t responseCode;
|
||||
grub_uint32_t parameterSize;
|
||||
|
||||
if (eventData == NULL)
|
||||
return TPM_RC_VALUE;
|
||||
if (authCommand == NULL)
|
||||
return TPM_RC_VALUE;
|
||||
|
||||
if (digests == NULL)
|
||||
digests = &digestsTmp;
|
||||
if (authResponse == NULL)
|
||||
authResponse = &authResponseTmp;
|
||||
|
||||
/* Marshal */
|
||||
grub_tpm2_buffer_init (&in);
|
||||
grub_tpm2_buffer_pack_u32 (&in, pcrHandle);
|
||||
grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
|
||||
grub_Tss2_MU_TPM2B_Marshal (&in, eventData->size, eventData->buffer);
|
||||
if (in.error == true)
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
rc = tpm2_submit_command (TPM_ST_SESSIONS, TPM_CC_PCR_Event, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
if (responseCode != TPM_RC_SUCCESS)
|
||||
return responseCode;
|
||||
|
||||
/* Unmarshal */
|
||||
grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
|
||||
grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (&out, digests);
|
||||
grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
|
||||
if (out.error == true)
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
return TPM_RC_SUCCESS;
|
||||
}
|
||||
|
||||
TPM_RC_t
|
||||
grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
|
||||
const TPML_PCR_SELECTION_t *pcrSelectionIn,
|
||||
@ -615,7 +658,6 @@ grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_PCR_Read, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -668,7 +710,6 @@ grub_tpm2_policygetdigest (const TPMI_SH_POLICY_t policySession,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_PolicyGetDigest, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -751,7 +792,6 @@ grub_tpm2_create (const TPMI_DH_OBJECT_t parentHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_Create, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -805,7 +845,6 @@ grub_tpm2_evictcontrol (const TPMI_RH_PROVISION_t auth,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_EvictControl, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -871,7 +910,6 @@ grub_tpm2_hash (const TPMS_AUTH_COMMAND_t *authCommand,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_Hash, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -930,7 +968,6 @@ grub_tpm2_verifysignature (const TPMI_DH_OBJECT_t keyHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_VerifySignature, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -990,7 +1027,6 @@ grub_tpm2_policyauthorize (const TPMI_SH_POLICY_t policySession,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_PolicyAuthorize, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -1031,7 +1067,6 @@ grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_TestParms, &responseCode, &in,
|
||||
&out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
@ -1075,7 +1110,6 @@ grub_tpm2_nv_definespace (const TPMI_RH_PROVISION_t authHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_NV_DefineSpace, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -1110,7 +1144,6 @@ grub_tpm2_nv_undefinespace (const TPMI_RH_PROVISION_t authHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_NV_UndefineSpace, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -1146,7 +1179,6 @@ grub_tpm2_nv_readpublic (const TPMI_RH_NV_INDEX_t nvIndex,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_NV_ReadPublic, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -1191,7 +1223,6 @@ grub_tpm2_nv_read (const TPMI_RH_NV_AUTH_t authHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_NV_Read, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
@ -1233,7 +1264,6 @@ grub_tpm2_nv_write (const TPMI_RH_NV_AUTH_t authHandle,
|
||||
return TPM_RC_FAILURE;
|
||||
|
||||
/* Submit */
|
||||
grub_tpm2_buffer_init (&out);
|
||||
rc = tpm2_submit_command (tag, TPM_CC_NV_Write, &responseCode, &in, &out);
|
||||
if (rc != TPM_RC_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -89,6 +89,13 @@ grub_tpm2_unseal (const TPMI_DH_OBJECT_t item_handle,
|
||||
extern TPM_RC_t
|
||||
grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle);
|
||||
|
||||
extern TPM_RC_t
|
||||
grub_tpm2_pcr_event (const TPMI_DH_PCR_t pcrHandle,
|
||||
const TPMS_AUTH_COMMAND_t *authCommand,
|
||||
const TPM2B_EVENT_t *eventData,
|
||||
TPML_DIGEST_VALUES_t *digests,
|
||||
TPMS_AUTH_RESPONSE_t *authResponse);
|
||||
|
||||
extern TPM_RC_t
|
||||
grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
|
||||
const TPML_PCR_SELECTION_t *pcrSelectionIn,
|
||||
|
||||
@ -1118,6 +1118,24 @@ grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
|
||||
grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &digest->digests[i]);
|
||||
}
|
||||
|
||||
void
|
||||
grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
|
||||
TPML_DIGEST_VALUES_t *digests)
|
||||
{
|
||||
grub_uint32_t i;
|
||||
|
||||
grub_tpm2_buffer_unpack_u32 (buffer, &digests->count);
|
||||
|
||||
if (digests->count > TPM_NUM_PCR_BANKS)
|
||||
{
|
||||
buffer->error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < digests->count; i++)
|
||||
grub_Tss2_MU_TPMT_HA_Unmarshal (buffer, &digests->digests[i]);
|
||||
}
|
||||
|
||||
void
|
||||
grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
|
||||
TPMS_SIGNATURE_RSA_t *rsa)
|
||||
|
||||
@ -380,6 +380,10 @@ extern void
|
||||
grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
|
||||
TPML_DIGEST_t *digest);
|
||||
|
||||
extern void
|
||||
grub_Tss2_MU_TPML_DIGEST_VALUE_Unmarshal (grub_tpm2_buffer_t buffer,
|
||||
TPML_DIGEST_VALUES_t *digests);
|
||||
|
||||
extern void
|
||||
grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
|
||||
TPMS_SIGNATURE_RSA_t *p);
|
||||
|
||||
@ -144,6 +144,13 @@ typedef struct TPML_DIGEST TPML_DIGEST_t;
|
||||
/* TPM2B_NONCE Type */
|
||||
typedef TPM2B_DIGEST_t TPM2B_NONCE_t;
|
||||
|
||||
/* TPM2B_EVENT Structure */
|
||||
struct TPM2B_EVENT {
|
||||
grub_uint16_t size;
|
||||
grub_uint8_t buffer[1024];
|
||||
};
|
||||
typedef struct TPM2B_EVENT TPM2B_EVENT_t;
|
||||
|
||||
/* TPMA_SESSION Structure */
|
||||
struct TPMA_SESSION
|
||||
{
|
||||
|
||||
@ -343,6 +343,7 @@ typedef grub_uint32_t TPM_CC_t;
|
||||
#define TPM_CC_NV_Write ((TPM_CC_t) 0x00000137)
|
||||
#define TPM_CC_NV_UndefineSpace ((TPM_CC_t) 0x00000122)
|
||||
#define TPM_CC_GetCapability ((TPM_CC_t) 0x0000017a)
|
||||
#define TPM_CC_PCR_Event ((TPM_CC_t) 0x0000013c)
|
||||
#define TPM_CC_PCR_Read ((TPM_CC_t) 0x0000017e)
|
||||
#define TPM_CC_Load ((TPM_CC_t) 0x00000157)
|
||||
#define TPM_CC_LoadExternal ((TPM_CC_t) 0x00000167)
|
||||
|
||||
246
grub-core/lib/x86_64/efi/hwfeatures-gcry.c
Normal file
246
grub-core/lib/x86_64/efi/hwfeatures-gcry.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2025 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/x86_64/efi/hwfeatures-gcry.h>
|
||||
#include <grub/x86_64/cpuid.h>
|
||||
#include <grub/misc.h>
|
||||
|
||||
/*
|
||||
* Older versions of GCC may reorder the inline asm, which can lead to
|
||||
* unexpected behavior when reading the Control Registers. The __FORCE_ORDER
|
||||
* macro is used to prevent this.
|
||||
*
|
||||
* Ref: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=aa5cacdc29d76a005cbbee018a47faa6e724dd2d
|
||||
*/
|
||||
#define __FORCE_ORDER "m"(*(unsigned int *) 0x1000UL)
|
||||
|
||||
#define HW_FEATURE_X86_64_SSE (1 << 0)
|
||||
#define HW_FEATURE_X86_64_AVX (1 << 1)
|
||||
|
||||
static grub_uint32_t hw_features = 0;
|
||||
static grub_uint64_t old_cr0, old_cr4, old_xcr0;
|
||||
|
||||
static grub_uint64_t
|
||||
read_cr0 (void)
|
||||
{
|
||||
grub_uint64_t val;
|
||||
|
||||
asm volatile ("mov %%cr0, %0" : "=r" (val) : __FORCE_ORDER);
|
||||
return val;
|
||||
}
|
||||
|
||||
static grub_uint64_t
|
||||
read_cr4 (void)
|
||||
{
|
||||
grub_uint64_t val;
|
||||
|
||||
asm volatile ("mov %%cr4,%0" : "=r" (val) : __FORCE_ORDER);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void
|
||||
write_cr0 (grub_uint64_t val)
|
||||
{
|
||||
asm volatile ("mov %0,%%cr4": "+r" (val) : : "memory");
|
||||
}
|
||||
|
||||
static void
|
||||
write_cr4 (grub_uint64_t val)
|
||||
{
|
||||
asm volatile ("mov %0,%%cr4": "+r" (val) : : "memory");
|
||||
}
|
||||
|
||||
static grub_uint32_t
|
||||
get_cpuid_ecx (void)
|
||||
{
|
||||
grub_uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
grub_cpuid (1, eax, ebx, ecx, edx);
|
||||
|
||||
return ecx;
|
||||
}
|
||||
|
||||
static grub_uint32_t
|
||||
get_cpuid_edx (void)
|
||||
{
|
||||
grub_uint32_t eax, ebx, ecx, edx;
|
||||
|
||||
grub_cpuid (1, eax, ebx, ecx, edx);
|
||||
|
||||
return edx;
|
||||
}
|
||||
|
||||
static bool
|
||||
enable_sse (void)
|
||||
{
|
||||
grub_uint64_t cr0, cr4;
|
||||
grub_uint32_t edx;
|
||||
|
||||
edx = get_cpuid_edx ();
|
||||
|
||||
/* Check CPUID.01H:EDX.FXSR[bit 24] and CPUID.01H:EDX.SSE[bit 25] */
|
||||
if ((edx & (3 << 24)) != (3 << 24))
|
||||
return false;
|
||||
|
||||
cr0 = old_cr0 = read_cr0 ();
|
||||
cr4 = old_cr4 = read_cr4 ();
|
||||
|
||||
/* clear CR0.EM[bit 2] */
|
||||
if ((cr0 & (1 << 2)) != 0)
|
||||
cr0 &= ~(1 << 2);
|
||||
|
||||
/* Set CR0.MP[bit 1] */
|
||||
if ((cr0 & (1 << 1)) == 0)
|
||||
cr0 |= (1 << 1);
|
||||
|
||||
grub_dprintf ("hwfeatures", "CR0: 0x%"PRIxGRUB_UINT64_T" 0x%"PRIxGRUB_UINT64_T"\n", old_cr0, cr0);
|
||||
if (old_cr0 != cr0)
|
||||
write_cr0 (cr0);
|
||||
|
||||
/* Set CR4.OSFXSR[bit 9] and CR4.OSXMMEXCPT[bit 10] */
|
||||
if ((cr4 & (3 << 9)) != (3 << 9))
|
||||
cr4 |= (3 << 9);
|
||||
|
||||
grub_dprintf ("hwfeatures", "CR4: 0x%"PRIxGRUB_UINT64_T" 0x%"PRIxGRUB_UINT64_T"\n", old_cr4, cr4);
|
||||
if (old_cr4 != cr4)
|
||||
write_cr4 (cr4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static grub_uint64_t
|
||||
xgetbv (grub_uint32_t index)
|
||||
{
|
||||
grub_uint32_t eax, edx;
|
||||
|
||||
asm volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (index));
|
||||
|
||||
return eax + ((grub_uint64_t)edx << 32);
|
||||
}
|
||||
|
||||
static void
|
||||
xsetbv (grub_uint32_t index, grub_uint64_t value)
|
||||
{
|
||||
grub_uint32_t eax = (grub_uint32_t)value;
|
||||
grub_uint32_t edx = (grub_uint32_t)(value >> 32);
|
||||
|
||||
asm volatile ("xsetbv" :: "a" (eax), "d" (edx), "c" (index));
|
||||
}
|
||||
|
||||
static bool
|
||||
enable_avx (void)
|
||||
{
|
||||
grub_uint64_t cr4;
|
||||
grub_uint32_t ecx;
|
||||
grub_uint64_t sse_avx_mask = (1 << 2) | (1 << 1);
|
||||
grub_uint64_t xcr0;
|
||||
|
||||
ecx = get_cpuid_ecx ();
|
||||
|
||||
/* Check the following two bits
|
||||
* - CPUID.01H:ECX.XSAVE[bit 26]
|
||||
* If XSAVE is not supported, setting CR4.OSXSAVE will cause
|
||||
* general-protection fault (#GP).
|
||||
* - CPUID.01H:ECX.AVX[bit 28]
|
||||
*/
|
||||
grub_dprintf ("hwfeatures", "Check CPUID.01H:ECX 0x%"PRIuGRUB_UINT32_T"\n", ecx);
|
||||
if ((ecx & (5 << 26)) != (5 << 26))
|
||||
return false;
|
||||
|
||||
cr4 = read_cr4 ();
|
||||
|
||||
/* Set CR4.OSXSAVE[bit 18] */
|
||||
if ((cr4 & (1 << 18)) == 0)
|
||||
{
|
||||
grub_dprintf ("hwfeatures", "Set CR4.OSXSAVE\n");
|
||||
cr4 |= 1 << 18;
|
||||
write_cr4 (cr4);
|
||||
}
|
||||
|
||||
ecx = get_cpuid_ecx ();
|
||||
|
||||
/* Check CPUID.01H:ECX.OSXSAVE[bit 27] */
|
||||
if ((ecx & (1 << 27)) == 0)
|
||||
return false;
|
||||
|
||||
xcr0 = old_xcr0 = xgetbv (0);
|
||||
|
||||
/* Set XCR0[bit 1] and XCR0[bit 2] to enable SSE/AVX */
|
||||
if ((xcr0 & sse_avx_mask) != sse_avx_mask)
|
||||
{
|
||||
grub_dprintf ("hwfeatures", "Set XCR0[2:1] to 11b\n");
|
||||
xcr0 |= sse_avx_mask;
|
||||
xsetbv (0, xcr0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
grub_enable_gcry_hwf_x86_64_efi (void)
|
||||
{
|
||||
if (enable_sse () == true)
|
||||
hw_features |= HW_FEATURE_X86_64_SSE;
|
||||
|
||||
if (enable_avx () == true)
|
||||
hw_features |= HW_FEATURE_X86_64_AVX;
|
||||
}
|
||||
|
||||
void
|
||||
grub_reset_gcry_hwf_x86_64_efi (void)
|
||||
{
|
||||
grub_uint64_t cr0, cr4, xcr0;
|
||||
|
||||
if ((hw_features & HW_FEATURE_X86_64_AVX) != 0)
|
||||
{
|
||||
xcr0 = xgetbv (0);
|
||||
if (xcr0 != old_xcr0)
|
||||
{
|
||||
/*
|
||||
* Reset the AVX state with 'vzeroupper' before clearing XCR0[bit 2].
|
||||
*
|
||||
* Ref: Intel 64 and IA-32 Architectures Software Developer's Manual
|
||||
* - 13.3 ENABLING THE XSAVE FEATURE SET AND XSAVE-ENABLED FEATURES
|
||||
*
|
||||
* "As noted in Section 13.1, the processor will preserve AVX state
|
||||
* unmodified if software clears XCR0[2]. However, clearing XCR0[2]
|
||||
* while AVX state is not in its initial configuration may cause SSE
|
||||
* instructions to incur a power and performance penalty."
|
||||
*/
|
||||
asm volatile ("vzeroupper" ::: "memory");
|
||||
xsetbv (0, old_xcr0);
|
||||
}
|
||||
}
|
||||
|
||||
if ((hw_features & HW_FEATURE_X86_64_AVX) != 0 || (hw_features & HW_FEATURE_X86_64_SSE) != 0)
|
||||
{
|
||||
cr4 = read_cr4 ();
|
||||
if (cr4 != old_cr4)
|
||||
write_cr4 (old_cr4);
|
||||
}
|
||||
|
||||
if ((hw_features & HW_FEATURE_X86_64_SSE) != 0)
|
||||
{
|
||||
cr0 = read_cr0 ();
|
||||
if (cr0 != old_cr0)
|
||||
write_cr0 (old_cr0);
|
||||
}
|
||||
|
||||
hw_features = 0;
|
||||
}
|
||||
@ -36,7 +36,7 @@ GRUB_MOD_LICENSE "GPLv3+"
|
||||
*/
|
||||
FUNCTION(grub_setjmp)
|
||||
pop %rsi /* Return address, and adjust the stack */
|
||||
xorq %rax, %rax
|
||||
xorl %eax, %eax
|
||||
movq %rbx, 0(%rdi) /* RBX */
|
||||
movq %rsp, 8(%rdi) /* RSP */
|
||||
push %rsi
|
||||
|
||||
@ -387,8 +387,7 @@ static enum xz_ret hash_validate(struct xz_dec *s, struct xz_buf *b,
|
||||
&& sizeof (s->hash_value) >= hash->mdlen)
|
||||
{
|
||||
hash->final(hash_context);
|
||||
grub_memcpy (s->hash_value, hash->read(hash_context),
|
||||
hash->mdlen);
|
||||
memcpy (s->hash_value, hash->read (hash_context), hash->mdlen);
|
||||
s->have_hash_value = 1;
|
||||
if (s->hash_id == 1 || crc32)
|
||||
{
|
||||
|
||||
@ -174,7 +174,7 @@ prepare_xen_module_params (struct xen_boot_binary *module, void *xen_boot_fdt)
|
||||
module->cmdline, module->cmdline, module->cmdline_size);
|
||||
|
||||
retval = grub_fdt_set_prop (xen_boot_fdt, module_node, "bootargs",
|
||||
module->cmdline, module->cmdline_size + 1);
|
||||
module->cmdline, module->cmdline_size);
|
||||
if (retval)
|
||||
return grub_error (GRUB_ERR_IO, "failed to update FDT");
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user