* [PATCH v19 00/33] Automatic Disk Unlock with TPM2
@ 2024-09-06 9:10 Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 01/33] posix_wrap: tweaks in preparation for libtasn1 Gary Lin via Grub-devel
` (34 more replies)
0 siblings, 35 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
Hernan Gatta to introduce the key protector framework and TPM2 stack
to GRUB2, and this could be a useful feature for the systems to
implement full disk encryption.
To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
Daniel Axtens's "appended signature secure boot support" (*3) to import
libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
4.19.0 instead of 4.16.0 in the original patch.
Patch 8 fixes a potential buffer overrun in libtasn1.
(https://gitlab.com/gnutls/libtasn1/-/issues/49)
Patch 17 adds the document for libtasn1 and the steps to upgrade the
library.
Patch 18~24 are based on Hernan Gatta's patches with the follow-up fixes
and improvements:
- Converting 8 spaces into 1 tab
- Merging the minor build fix from Michael Chang
- Replacing "lu" with "PRIuGRUB_SIZE" for grub_dprintf
- Adding "enable = efi" to the tpm2 module in grub-core/Makefile.core.def
- Rebasing "cryptodisk: Support key protectors" to the git master
- Removing the measurement on the sealed key
- Based on the patch from Olaf Kirch <OKir@suse.com>
- Adjusting the input parameters of TPM2_EvictControl to match the order
in "TCG TPM2 Part3 Commands"
- Declaring the input arguments of TPM2 functions as const
- Resending TPM2 commands on TPM_RC_RETRY
- Adding checks for the parameters of TPM2 commands
- Packing the missing authorization command for TPM2_PCR_Read
- Tweaking the TPM2 command functions to allow some parameters to be
NULL so that we don't have to declare empty variables
- Using grub_cpu_to_be*() in the TPM2 stack instead of grub_swap_bytes*()
which may cause problems in big-indian machines
- Changing the short name of "--protector" of "cryptomount" from "-k" to
"-P" to avoid the conflict with "--key-file"
- Supporting TPM 2.0 Key File Format besides the raw sealed key
- Adding the external libtasn1 dependency to grub-protect to write the
TPM 2.0 Key files
- Extending the TPM2 TSS stack to support authorized policy
Patch 25 implements the authorized policy support.
Patch 26 implements the missing NV index mode. (Thanks to Patrick Colp)
Patch 27 improves the 'cryptomount' command to fall back to the
passphrase mode when the key protector fails to unlock the encrypted
partition. (Another patch from Patrick Colp)
Patch 28 and 29 fix the potential security issues spotted by Fabian Vogt.
Patch 30 and 31 implement the TPM2 key unsealing testcases.
Patch 32 document the new "-P" option for "cryptomount"
Patch 33 document TPM2 key protector including the new GRUB commands and
the user-space utility.
To utilize the TPM2 key protector to unlock the encrypted partition
(sdb1), here are the sample steps:
1. Add an extra random key for LUKS (luks-key)
$ dd if=/dev/urandom of=luks-key bs=1 count=32
$ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2
2. Seal the key
$ sudo grub-protect --action=add \
--protector=tpm2 \
--tpm2key \
--tpm2-keyfile=luks-key \
--tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm
3. Unseal the key with the proper commands in grub.cfg:
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
cryptomount -u <SDB1_UUID> -P tpm2
(*1) https://lists.gnu.org/archive/html/grub-devel/2022-02/msg00006.html
(*2) https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
(*3) https://lists.gnu.org/archive/html/grub-devel/2021-06/msg00044.html
v19:
- Updating the coverity report for libtasn1
- Splitting the strcat() patch for libtasn1
- Addressing why the header paths are adjusted in libtasn1.h
- Fixing the order of the copyright headers
- Breaking down the patch for asn1 tests into the smaller patches
- libtasn1 patches are created by the following repo against the
libtasn1-4.19.0-base-v3 tag:
https://github.com/lcp/grub2/tree/import-libtasn1-4.19.0-v3
- Marking the 'extern' functions
- Amending the string length checks
- Unmarking the technical strings for translation
- Fixing more line foldings and coding style issues
- Renaming the TPM2 types to add the '_t' postfix for typedefs
- Adding the 'grub_' prefix to the global functions from tss2 and
removing the 'grub_' prefix from the location functions
- Adding more comments about the passphrase fallback
- Simplying the diskfilter check
- Documenting TPM2 key protector in the user manual
v18:
- https://lists.gnu.org/archive/html/grub-devel/2024-06/msg00228.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v18
- Updating the steps to import libtasn1
- Importing test cases from libtasn1 and then applying the follow-up
patch by autogen.sh
- The patch files in patch 3~8 are created with the following repo
against the libtasn1-4.19.0-base-v2 tag:
https://github.com/lcp/grub2/tree/import-libtasn1-4.19.0-v2
- Splitting the grub compatibility patch for libtasn1
- Moving the TSS2 code to grub-core/lib/tss2 and renaming
grub_tpm2_mu_*() functions to grub_Tss2_MU_*()
- Splitting the TSS2 patch into 3 patches
- Fixing the types of TPMA_SESSION, TPMA_OBJECT, and TPMA_LOCALITY
- Renaming the tpm2 module to tpm2_key_protector
- Adding more comments to asn1_read_uint32() and defining the lower and
upper bounds for tpm2key elements
- Also fixing a bug that allows 100 elements in the key file
- Fixing the copyright headers
- Fixing the coding style
v17:
- https://lists.gnu.org/archive/html/grub-devel/2024-06/msg00108.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v17
- Fixing the missing space in strncat()
- Updating the steps to import libtasn1
- Moving libtasn1.h to grub-core/lib/libtasn1/ and fixing the affected
patches
- libtasn1.h is included in tpm2key.h, so there is no need to include
the header again in module.c and tpm2key.c.
- Applying the libtasn1 patches in a different way
- Instead of applying the patches directly in the grub2 source code,
libtasn1 is copied to grub-core/lib/libtasn1-grub by autogen.sh and
then the script applies the libtasn1 patches to libtasn1-grub.
- The patch files in patch 3, 4, and 5 are created by the following
repo against the libtasn1-4.19.0-base tag.
https://github.com/lcp/grub2/tree/import-libtasn1-4.19.0
- Correcting the description of the tpm2_test commit to replace
swtpm_cuse with "swtpm chardev"
v16:
- https://lists.gnu.org/archive/html/grub-devel/2024-05/msg00093.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v16
- Rebasing patch 6, 12, and 16 to fix the conflicts with the latest
master branch
- Changes in cryptodisk:
- Disallowing that both OPTION_KEYFILE and OPTION_PROTECTOR are set
since the key data for "--key-file" would be overwritten by the key
protectors
- Resetting the cargs key data when the key from a key protector
doesn't work for the disk to ensure the passphrase prompt will be
triggered later
- Adding the comment to address why grub_errno is only cleared for
cargs->key_len == 0
v15:
- https://lists.gnu.org/archive/html/grub-devel/2024-05/msg00059.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v15
- Changes in tpm2_test
- Quoting the variables which contain file paths
- Correcting the exit code for several commands
- Writing the verification text directly into the LUKS device
- Amending the waiting loop for swtpm
- Replacing exit with return in tpm2_seal_unseal() and
tpm2_seal_unseal_nv()
- Collecting the parameters for the SRK mode testcases in an array
and invoking tpm2_seal_unseal() with a for loop
- Moving the tpm2-tools commands for the NV index mode to a separate
function
- Using tpm2_evictcontrol to remove the object from the NV index to
match the key sealing commands
- Printing the test results
- Printing error messages to stderr
v14:
- https://lists.gnu.org/archive/html/grub-devel/2024-05/msg00011.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v14
- Addressing the libtasn1 patches more in the document
- Various improvements in tpm2_test
- Verifying the test inside the LUKS device
- Improving the return status checks and the waiting loop for swtpm
- Fixing the portability issues
- Making all variables braced
- Renaming grub-emu-opts to --emu-opts (grub-shell)
v13:
- https://lists.gnu.org/archive/html/grub-devel/2024-04/msg00155.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v13
- Fixing typos and a few multi-line comments
- Improving the conditional checks for the arguments of
tpm2_key_protector_init
- Updating to the latest TPM 2.0 Key File format
- Adding the new optional fields: description and rsaParent
- Handling "rsaParent == TRUE" when unsealing the tpm2key
- Setting "rsaParent" to "TRUE" when sealing the key with RSA SRK
- Removing non-standard SRKs: RSA3072, RSA4096, ECC_NIST_P384,
ECC_NIST_P521, and ECC_SM2_P256
- Adding more error messages to grub-protect
- Improving the error checking for the swtpm chardev instance
- Exiting the tpm2_test script if grub-protect failed to seal the key
v12:
- https://lists.gnu.org/archive/html/grub-devel/2024-04/msg00108.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v12
- Fixing typos and indentation
- Removing the unused TPM commands: TPM2_HashSequenceStart,
TPM2_SequenceUpdate, and TPM2_SequenceComplete,
- Following the TCG EK templates to set the parameters of SRK
- Removing ECC_BN_P256 and ECC_BN_P638 from the SRK algorithm list since
those two algorithms are not mentioned in the TCG EK templates
- Updating the help messages of the tpm2 module and grub-protect
- Removing the unnecessary NULL checks
- Adding the manpage for grub-protect
- Replacing grub_crypto_hash() with TPM2_Hash() in grub-protect to
support SHA384 PCR banks
- Using 'swtpm chardev' to start swtpm instead of 'swtpm_cuse' since
some distros may not build swtpm with cuse
- Adding a new testcase without specifying the SRK type to test the
default SRK settings
- Amending tpm2_test to remove the duplicate error checking code
- Silencing the tpm2-tools commands in tpm2_test
- Fixing the exit trap of tpm2_test to removing the working directory
on success
v11:
- https://lists.gnu.org/archive/html/grub-devel/2024-04/msg00052.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v11
- Adding the missing default: handlers in grub-core/tpm2/mu.c
- Updating the help messages and commit messages to reflect the change
of the default SRK algorithm (RSA2048 -> ECC_NIST_P256)
- Adding the testcase for the NV index mode
v10:
- https://lists.gnu.org/archive/html/grub-devel/2024-04/msg00019.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v10
- Fixing the coverity issues: CID 435775, CID 435771, CID 435770, CID
435769, CID 435767, CID 435761
https://lists.gnu.org/archive/html/grub-devel/2024-02/txtKIuUb5lf3O.txt
- Fixing the potential memory leak (CID 435775)
- Removing the unnecessary grub_protect_get_grub_drive_for_file() from
util/grub-protect.c (CID 435771)
- Using the grub_tpm2_mu_TPM2B_*_Unmarshal functions to unmarshal the
TPM2B structs instead of a generic grub_tpm2_mu_TPM2B_Unmarshal
(CID 435770)
- Fixing Null pointer dereference (CID 435769)
- Adding bound checks to grub_tpm2_mu_TPML_DIGEST_Unmarshal()
(CID 435767)
- Improving the check for the return value of ftell() (CID 435761)
- Adding a quick fix for CID 435762
- Removing the empty ending line in tests/asn1_test.in
- Fixing docs/grub-dev.texi and updating the libtasn1 patches in
grub-core/lib/libtasn1-patches/
- Merging all the TPM2 TSS stack patches into one to reduce the total
patch number
- Switching the default asymmetric algorithm from RSA2048 to
TPM_ECC_NIST_P256 for the faster key generation
- Adding the fallback SRK templates to try a few more SRK types in case
grub2 failed to associate the sealed key with the SRK in the persistent
handle or the default SRK
- Improving the test script to add tests for the persistent handle and
the fallback SRKs
v9:
- https://lists.gnu.org/archive/html/grub-devel/2024-02/msg00007.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v9
- Introducing c-ctype.h to posix_wrap and implementing strncat
- Adding the descriptive comments to the disabled code in libtasn1
- Replacing strcat with the bound-checked _asn1_str_cat in libtasn1 and
including c-ctype.h directly
- Integrating the asn1 testcases into "functional_test"
- Updating the libtasn1 patches mentioned in the documentation
- Moving the key protector to a module
- Amending configure.ac to enable/disable grub-protect
- Fixing an timeout issue in the tpm2_test script by feeding the config
through stdin
v8:
- https://lists.gnu.org/archive/html/grub-devel/2024-01/msg00013.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v8
- Introducing TPM device support to grub-emu and adding the TPM key
unsealing testcase
v7:
- https://lists.gnu.org/archive/html/grub-devel/2023-11/msg00127.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v7
- Stopping reading SRK from the well-known persistent handle (TPM2_SRK_HANDLE,
i.e. 0x81000001) by default since the persistent handle may be created
by other OS and causes unsealing failure due to SRK mismatching
- The user now has to specify the persistent handle with "--srk"
explicitly.
- Utilizing grub_error() to print more error messages
- Unifying the format of the error messages from TPM2 commands
v6:
- https://lists.gnu.org/archive/html/grub-devel/2023-10/msg00026.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v6
- Supporting more SRK types than RSA2048 and ECC_NIST_P256
- Documenting SHA512 as the supported PCR bank type in the tpm2
protector
- Removing the redundant error message for grub_tpm2_protector_srk_get()
since it may overwrite the real error message.
- Updating the supported SRK types and PCR bank types in grub-protect
- Removing the unused type: TPM2_ECC_CURVE
v5:
- https://lists.gnu.org/archive/html/grub-devel/2023-08/msg00113.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v5
- Rebasing to the latest git HEAD and improving the commit messages
- Implementing authorized poilcy support
- Implementing NV index mode
- Improving the 'cryptomount' command to fall back to the passphrase
mode when the key protector fails to unlock the encrypted partition
- Fixing the potential security issues
v4:
- https://lists.gnu.org/archive/html/grub-devel/2023-04/msg00104.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v4
- Improving the error condition checks in cryptodisk.c
- Moving the code to unseal with the standalone policy sequence below
the code for authpolicy sequence
- The standalone policy sequence was mistakenly prepended to to the
authpolicy sequence with grub_list_push() while it should be
appended.
- Pushing the error messages from the authpolicy sequence into the
grub_error stack so that we can list all errors from the sequence
- Improving the error messages in the TPM2 protector
- Amending the calculation of the max string lengths of 'Policy',
'CommandCode' and 'CommandPolicy'
- Skipping the error path in grub_tpm2key_get_authpolicy_seq() on
success to avoid freeing the authpolicy sequence
v3:
- https://lists.gnu.org/archive/html/grub-devel/2023-04/msg00055.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v3
- Adding the document for libtasn1
- Improving the error condition checks
ex: "if (!ptr)" ==> "if (ptr == NULL)"
"if (err)" ==> "if (err != GRUB_ERR_NONE)"
"if (rc)" ==> "if (rc != TPM_RC_SUCCESS)"
- Supporting the "TPMPolicy" and "TPMAuthPolicy" sequence in the TPM 2.0
key File
- Refactoring the key recover function to support "TPMPolicy" and
"TPMAuthPolicy" sequence
- Using TPMS_PCR_SELECTION_SelectPCR() to set the PCR bit mask
- Also dropping TPM2_PCR_TO_SELECT() and TPM2_PCR_TO_BIT() which are
not necessary anymore
- Removing the redundant variable, 'crd', from
grub_cryptodisk_scan_device_real()
- Fixing the spaces/tabs in cryptodisk.c
- Fixing the comment format in cryptodisk.h
- Adding the defensive check for "cargs->protectors" in
grub_cryptodisk_scan_device()
- Improving 'grub-protect' for the better support of TPM 2.0 Key File
- Adding more comments
v2:
- https://lists.gnu.org/archive/html/grub-devel/2023-03/msg00094.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock-v2
v1:
- https://lists.gnu.org/archive/html/grub-devel/2023-02/msg00130.html
- GIT repo: https://github.com/lcp/grub2/tree/tpm2-unlock
*********************************************
* Anaylses for Coverity issuses on libtasn1 *
*********************************************
2 Memory corruptions: CID 435762, CID 435766
________________________________________________________________________________________________________
*** CID 435762: Memory - corruptions (OVERRUN)
/grub-core/lib/libtasn1/lib/coding.c: 152 in _asn1_tag_der()
146 if (k > ASN1_MAX_TAG_SIZE - 1)
147 break; /* will not encode larger tags */
148 }
149 *ans_len = k + 1;
150 while (k--)
151 ans[*ans_len - 1 - k] = temp[k] + 128;
>>> CID 435762: Memory - corruptions (OVERRUN)
>>> Overrunning array of 4 bytes at byte offset 4 by dereferencing pointer "ans + (*ans_len - 1)".
152 ans[*ans_len - 1] -= 128;
153 }
154 }
155
156 /**
157 * asn1_octet_der:
Reported to upstream: https://gitlab.com/gnutls/libtasn1/-/issues/49
________________________________________________________________________________________________________
*** CID 435766: Memory - corruptions (OVERRUN)
/grub-core/lib/libtasn1/lib/decoding.c: 1204 in asn1_der_decoding2()
1198 }
1199
1200 DECR_LEN (ider_len, len2);
1201
1202 tlen = strlen (temp);
1203 if (tlen > 0)
>>> CID 435766: Memory - corruptions (OVERRUN)
>>> Allocating insufficient memory for the terminating null of the string.
1204 _asn1_set_value (p, temp, tlen);
1205
1206 counter += len2;
1207 move = RIGHT;
1208 break;
1209 case ASN1_ETYPE_OCTET_STRING:
False positive?
https://gitlab.com/gnutls/libtasn1/-/issues/50
==
7 Integer handling issues:
CID 435774, CID 435773, CID 435772, CID 435768, CID 435765, CID 435764, CID 435763
________________________________________________________________________________________________________
*** CID 435774: Integer handling issues (CONSTANT_EXPRESSION_RESULT)
/grub-core/lib/libtasn1/lib/decoding.c: 481 in asn1_get_object_id_der()
475 */
476 if (leading != 0 && der[len_len + k] == 0x80)
477 return ASN1_DER_ERROR;
478 leading = 0;
479
480 /* check for wrap around */
>>> CID 435774: Integer handling issues (CONSTANT_EXPRESSION_RESULT)
>>> "val < ((((1 ? 0 : val) - 1 < 0) ? ~((((1 ? 0 : val) + 1 << 62UL /* sizeof (+val) * 8 - 2 */) - 1) * 2 + 1) : ((1 ? 0 : val) + 0)) >> 7)" is always false regardless of the values of its operands. This occurs as the second operand of "?:".
481 if (INT_LEFT_SHIFT_OVERFLOW (val, 7))
482 return ASN1_DER_ERROR;
483
484 val = val << 7;
485 val |= der[len_len + k] & 0x7F;
486
/grub-core/lib/libtasn1/lib/decoding.c: 481 in asn1_get_object_id_der()
Here are the related macros from gnulib:
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \
((a) < 0 \
? (a) < (min) >> (b) \
: (max) >> (b) < (a))
#define INT_LEFT_SHIFT_OVERFLOW(a, b) \
INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \
_GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
The statement in question is expanded "(a) < (min) >> (b)" from
'INT_LEFT_SHIFT_RANGE_OVERFLOW'.
'(a) < (min) >> (b)'
=> '(val) < _GL_INT_MINIMUM (val) >> (7)'
=> '(val) < \
(EXPR_SIGNED (val) \
? ~ _GL_SIGNED_INT_MAXIMUM (val) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((_GL_INT_NEGATE_CONVERT (val, 1) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (val) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (val) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((_GL_INT_CONVERT (val, 1) << (TYPE_WIDTH (+ (val)) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((((1 ? 0 : (val)) + (1)) << (TYPE_WIDTH (+ (val)) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((((1 ? 0 : (val)) + (1)) << ((sizeof (val) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((((1 ? 0 : (val)) + (1)) << ((sizeof (val) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: ((1 ? 0 : (val)) + (0))) \
>> (7)'
'_GL_INT_MINIMUM' returns the minimum value of the given type. Since 'val' is
'uint64_t', '_GL_INT_MINIMUM (val)' is 0
'(val) < _GL_INT_MINIMUM (val) >> (7)' => '(val) < 0 >> (7)' => '(val) < 0'
For 'uint64_t val', the result is always false.
However, in 'INT_LEFT_SHIFT_RANGE_OVERFLOW':
((a) < 0 \
? (a) < (min) >> (b) \
: (max) >> (b) < (a))
'(a) < 0' is false for 'uint64_t val', so the second operand, '(a) < (min) >> (b)',
is always skipped. Thus, the result of the second operand doesn't matter.
________________________________________________________________________________________________________
*** CID 435773: Integer handling issues (NO_EFFECT)
/grub-core/lib/libtasn1/lib/decoding.c: 439 in asn1_get_object_id_der()
433 return ASN1_DER_ERROR;
434
435 val0 = 0;
436
437 for (k = 0; k < len; k++)
438 {
>>> CID 435773: Integer handling issues (NO_EFFECT)
>>> This less-than-zero comparison of an unsigned value is never true. "(1 ? 0UL : val0) - 1UL < 0UL".
439 if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
440 return ASN1_DER_ERROR;
441
442 val0 <<= 7;
443 val0 |= der[len_len + k] & 0x7F;
444 if (!(der[len_len + k] & 0x80))
Here are the related macros from gnulib:
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \
((a) < 0 \
? (a) < (min) >> (b) \
: (max) >> (b) < (a))
#define INT_LEFT_SHIFT_OVERFLOW(a, b) \
INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \
_GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
The statement in question is the expanded 'EXPR_SIGNED (val0)' from either
'_GL_INT_MAXIMUM' or '_GL_INT_MINIMUM'
'EXPR_SIGNED (val0)'
=> '(_GL_INT_NEGATE_CONVERT (val0, 1) < 0)'
=> '(((1 ? 0 : (val0)) - (1)) < 0)'
'EXPR_SIGNED' is designed to test if the given expression is signed, and
'EXPR_SIGNED (val0)' is expected to be false for 'uint64_t val0'. The macro
dutifully reflects the fact.
________________________________________________________________________________________________________
*** CID 435772: Integer handling issues (NO_EFFECT)
/grub-core/lib/libtasn1/lib/decoding.c: 204 in asn1_get_tag_der()
198 /* Long form */
199 punt = 1;
200 ris = 0;
201 while (punt < der_len && der[punt] & 128)
202 {
203
>>> CID 435772: Integer handling issues (NO_EFFECT)
>>> This less-than-zero comparison of an unsigned value is never true. "(1 ? 0U : ((1 ? 0U : ris) + 128U)) - 1U < 0U".
204 if (INT_MULTIPLY_OVERFLOW (ris, 128))
205 return ASN1_DER_ERROR;
206 ris *= 128;
207
208 if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
209 return ASN1_DER_ERROR;
Here are the related macros gnulib:
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \
((b) < 0 \
? ((a) < 0 \
? (a) < (max) / (b) \
: (b) == -1 \
? 0 \
: (min) / (b) < (a)) \
: (b) == 0 \
? 0 \
: ((a) < 0 \
? (a) < (min) / (b) \
: (max) / (b) < (a)))
# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
(((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \
|| INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \
op_result_overflow (a, b, \
_GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \
_GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
#define INT_MULTIPLY_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
The statement in question is the expanded 'EXPR_SIGNED (_GL_INT_CONVERT (ris, 128))'
from either '_GL_INT_MINIMUM' or '_GL_INT_MAXIMUM'.
'EXPR_SIGNED (_GL_INT_CONVERT (ris, 128))'
=> 'EXPR_SIGNED ((1 ? 0 : (ris)) + (128))'
=> '(_GL_INT_NEGATE_CONVERT (((1 ? 0 : (ris)) + (128), 1) < 0))'
=> '((1 ? 0 : ((1 ? 0 : ris) + 128)) - 1 < 0)'
'_GL_INT_CONVERT(e, v)' returns a value with the common real type of 'e' and 'v' and
the value of 'v'. Since the common type of 'unsigned int ris' and '128' is
'unsigned int', '_GL_INT_CONVERT (ris, 128)' is '128U'.
'EXPR_SIGNED' is designed to check if the given expression is signed. Thus,
'EXPR_SIGNED (128U)' is expected to be false.
The combination of 'EXPR_SIGNED(e)' and '_GL_INT_CONVERT(e, v)' is used to test if
the common type of the given two variables is signed, and those macros dutifully
reflect the fact: the common type of 'ris' and '128' is unsigned.
________________________________________________________________________________________________________
*** CID 435768: (CONSTANT_EXPRESSION_RESULT)
/grub-core/lib/libtasn1/lib/decoding.c: 204 in asn1_get_tag_der()
198 /* Long form */
199 punt = 1;
200 ris = 0;
201 while (punt < der_len && der[punt] & 128)
202 {
203
>>> CID 435768: (CONSTANT_EXPRESSION_RESULT)
>>> "ris < (((1 ? 0 : ((1 ? 0 : ris) + 128)) - 1 < 0) ? ~((((1 ? 0 : ((1 ? 0 : ris) + 128)) + 1 << 30UL /* sizeof (+((1 ? 0 : ris) + 128)) * 8 - 2 */) - 1) * 2 + 1) : ((1 ? 0 : ((1 ? 0 : ris) + 128)) + 0)) / 128" is always false regardless of the values of its operands. This occurs as the second operand of "?:".
204 if (INT_MULTIPLY_OVERFLOW (ris, 128))
205 return ASN1_DER_ERROR;
206 ris *= 128;
207
208 if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
209 return ASN1_DER_ERROR;
/grub-core/lib/libtasn1/lib/decoding.c: 217 in asn1_get_tag_der()
211 punt++;
212 }
213
214 if (punt >= der_len)
215 return ASN1_DER_ERROR;
216
>>> CID 435768: (CONSTANT_EXPRESSION_RESULT)
>>> "ris < (((1 ? 0 : ((1 ? 0 : ris) + 128)) - 1 < 0) ? ~((((1 ? 0 : ((1 ? 0 : ris) + 128)) + 1 << 30UL /* sizeof (+((1 ? 0 : ris) + 128)) * 8 - 2 */) - 1) * 2 + 1) : ((1 ? 0 : ((1 ? 0 : ris) + 128)) + 0)) / 128" is always false regardless of the values of its operands. This occurs as the second operand of "?:".
217 if (INT_MULTIPLY_OVERFLOW (ris, 128))
218 return ASN1_DER_ERROR;
219 ris *= 128;
220
221 if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
222 return ASN1_DER_ERROR;
Here are the related macros gnulib:
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \
((b) < 0 \
? ((a) < 0 \
? (a) < (max) / (b) \
: (b) == -1 \
? 0 \
: (min) / (b) < (a)) \
: (b) == 0 \
? 0 \
: ((a) < 0 \
? (a) < (min) / (b) \
: (max) / (b) < (a)))
# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
(((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \
|| INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \
op_result_overflow (a, b, \
_GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \
_GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
#define INT_MULTIPLY_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
The statement in question is the expanded '(a) < (min) / (b)' from
'INT_MULTIPLY_RANGE_OVERFLOW'.
'(a) < (min) / (b)'
=> '(a) < (_GL_INT_MINIMUM (_GL_INT_CONVERT (a, b))) / (b)'
=> '(ris) < (_GL_INT_MINIMUM (_GL_INT_CONVERT (ris, 128))) / (128)'
=> '(ris) < \
(EXPR_SIGNED (_GL_INT_CONVERT (ris, 128)) \
? ~ _GL_SIGNED_INT_MAXIMUM (_GL_INT_CONVERT (ris, 128)) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((_GL_INT_NEGATE_CONVERT (_GL_INT_CONVERT (ris, 128), 1) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (_GL_INT_CONVERT (ris, 128)) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : (_GL_INT_CONVERT (ris, 128))) - (1)) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (_GL_INT_CONVERT (ris, 128)) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (_GL_INT_CONVERT (ris, 128)) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((_GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 1) << (TYPE_WIDTH (+ (_GL_INT_CONVERT (ris, 128))) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((((1 ? 0 : (_GL_INT_CONVERT (ris, 128))) + (1)) << (TYPE_WIDTH (+ (_GL_INT_CONVERT (ris, 128))) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) + (1)) << (TYPE_WIDTH (+ (_GL_INT_CONVERT (ris, 128))) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) + (1)) << ((sizeof (+ (_GL_INT_CONVERT (ris, 128))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) + (1)) << ((sizeof (+ ((1 ? 0 : (ris)) + (128))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) + (1)) << ((sizeof (+ ((1 ? 0 : (ris)) + (128))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ris, 128), 0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) + (1)) << ((sizeof (+ ((1 ? 0 : (ris)) + (128))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: ((1 ? 0 : (_GL_INT_CONVERT (ris, 128)) + (0)) \
/ (128)'
=> '(ris) < \
((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) - (1)) < 0) \
? ~ (((((1 ? 0 : ((1 ? 0 : (ris)) + (128))) + (1)) << ((sizeof (+ ((1 ? 0 : (ris)) + (128))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: ((1 ? 0 : ((1 ? 0 : (ris)) + (128)) + (0)) \
/ (128)'
'_GL_INT_CONVERT(e, v)' returns a value with the common real type of 'e' and 'v' and
the value of 'v'. Since the common type of 'unsigned int ris' and '128' is
'unsigned int', '_GL_INT_CONVERT (ris, 128)' is '128U'.
'_GL_INT_MINIMUM (128U)' returns the minimum value of 'unsigned int', i.e. 0.
'(ris) < (_GL_INT_MINIMUM (_GL_INT_CONVERT (ris, 128))) / (128)' => '(ris) < 0 / (128)' => '(ris) < 0'
For 'unsigned int ris', the result is always false.
However, in 'INT_MULTIPLY_RANGE_OVERFLOW', 'a' is 'unsigned int ris' and 'b' is '128'.
We can skip the statements for 'b < 0' and 'b == 0' and reduce the macro to
(a) < 0 \
? (a) < (min) / (b) \
: (max) / (b) < (a))) \
Since '(a) < 0' is false for 'unsigned int ris', the statement in question,
'(a) < (min) / (b)', is always skipped. Thus, the result of the statement doesn't
matter.
________________________________________________________________________________________________________
*** CID 435765: Integer handling issues (CONSTANT_EXPRESSION_RESULT)
/grub-core/lib/libtasn1/lib/decoding.c: 439 in asn1_get_object_id_der()
433 return ASN1_DER_ERROR;
434
435 val0 = 0;
436
437 for (k = 0; k < len; k++)
438 {
>>> CID 435765: Integer handling issues (CONSTANT_EXPRESSION_RESULT)
>>> "val0 < ((((1 ? 0 : val0) - 1 < 0) ? ~((((1 ? 0 : val0) + 1 << 62UL /* sizeof (+val0) * 8 - 2 */) - 1) * 2 + 1) : ((1 ? 0 : val0) + 0)) >> 7)" is always false regardless of the values of its operands. This occurs as the second operand of "?:".
439 if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
440 return ASN1_DER_ERROR;
441
442 val0 <<= 7;
443 val0 |= der[len_len + k] & 0x7F;
444 if (!(der[len_len + k] & 0x80))
Here are the related macros from gnulib:
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define INT_LEFT_SHIFT_RANGE_OVERFLOW(a, b, min, max) \
((a) < 0 \
? (a) < (min) >> (b) \
: (max) >> (b) < (a))
#define INT_LEFT_SHIFT_OVERFLOW(a, b) \
INT_LEFT_SHIFT_RANGE_OVERFLOW (a, b, \
_GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
The statement in question is expanded '(a) < (min) >> (b)' from
INT_LEFT_SHIFT_RANGE_OVERFLOW.
'(a) < (min) >> (b)'
=> '(val) < (_GL_INT_MINIMUM (val)) >> (7)'
=> '(val) < \
(EXPR_SIGNED (val) \
? ~ _GL_SIGNED_INT_MAXIMUM (val) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((_GL_INT_NEGATE_CONVERT (val, 1) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (val) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (val) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((_GL_INT_CONVERT (val, 1) << (TYPE_WIDTH (+ (val)) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((((1 ? 0 : (val)) + (1)) << (TYPE_WIDTH (+ (val)) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((((1 ? 0 : (val)) + (1)) << ((sizeof (+ (val)) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (val, 0)) \
>> (7)'
=> '(val) < \
((((1 ? 0 : (val)) - (1)) < 0) \
? ~ (((((1 ? 0 : (val)) + (1)) << ((sizeof (+ (val)) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: ((1 ? 0 : (val)) + (0))) \
>> (7)'
'_GL_INT_MINIMUM' returns the minimum value of the given type. For 'uint64_t val',
'_GL_INT_MINIMUM (val)' is 0.
'(val) < (_GL_INT_MINIMUM (val)) >> (7)' => '(val) < 0 >> (7)' => '(val) < 0'
For 'uint64_t val', the result is always false.
However, in 'INT_LEFT_SHIFT_RANGE_OVERFLOW':
((a) < 0 \
? (a) < (min) >> (b) \
: (max) >> (b) < (a))
'(a) < 0' is false for 'uint64_t val', so the statement in question,
'(a) < (min) >> (b)', is always skipped. Thus, the result of the statement doesn't
matter.
________________________________________________________________________________________________________
*** CID 435764: Integer handling issues (NO_EFFECT)
/grub-core/lib/libtasn1/lib/decoding.c: 137 in asn1_get_length_der()
131 punt = 1;
132 if (k)
133 { /* definite length method */
134 ans = 0;
135 while (punt <= k && punt < der_len)
136 {
>>> CID 435764: Integer handling issues (NO_EFFECT)
>>> This less-than-zero comparison of an unsigned value is never true. "(1 ? 0U : ((1 ? 0U : ans) + 256U)) - 1U < 0U".
137 if (INT_MULTIPLY_OVERFLOW (ans, 256))
138 return -2;
139 ans *= 256;
140
141 if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt])))
142 return -2;
Here are the related macros from gnulib:
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \
((b) < 0 \
? ((a) < 0 \
? (a) < (max) / (b) \
: (b) == -1 \
? 0 \
: (min) / (b) < (a)) \
: (b) == 0 \
? 0 \
: ((a) < 0 \
? (a) < (min) / (b) \
: (max) / (b) < (a)))
# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
(((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \
|| INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \
op_result_overflow (a, b, \
_GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \
_GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
#define INT_MULTIPLY_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
The statement in question is expanded 'EXPR_SIGNED (_GL_INT_CONVERT (ans, 256))'
from either '_GL_INT_MINIMUM' or '_GL_INT_MAXIMUM'.
'EXPR_SIGNED (_GL_INT_CONVERT (ans, 256))'
=> 'EXPR_SIGNED ((1 ? 0 : (ans)) + (256))'
=> '(_GL_INT_NEGATE_CONVERT (((1 ? 0 : (ans)) + (256)), 1) < 0)'
=> '((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1))'
'_GL_INT_CONVERT(e, v)' returns a value with the common real type of 'e' and 'v' and
the value of 'v'. Since the common type of 'unsigned int ans' and '256' is
'unsigned int', '_GL_INT_CONVERT (ans, 256)' is '256U'.
'EXPR_SIGNED' is designed to check if the given expression is signed. Thus,
'EXPR_SIGNED (256U)' is expected to be false.
The combination of 'EXPR_SIGNED(e)' and '_GL_INT_CONVERT(e, v)' is used to test if
the common type of the given two variables is signed, and those macros dutifully
reflect the fact: the common type of 'ans' and '256' is unsigned.
________________________________________________________________________________________________________
*** CID 435763: Integer handling issues (CONSTANT_EXPRESSION_RESULT)
/grub-core/lib/libtasn1/lib/decoding.c: 137 in asn1_get_length_der()
131 punt = 1;
132 if (k)
133 { /* definite length method */
134 ans = 0;
135 while (punt <= k && punt < der_len)
136 {
>>> CID 435763: Integer handling issues (CONSTANT_EXPRESSION_RESULT)
>>> "ans < (((1 ? 0 : ((1 ? 0 : ans) + 256)) - 1 < 0) ? ~((((1 ? 0 : ((1 ? 0 : ans) + 256)) + 1 << 30UL /* sizeof (+((1 ? 0 : ans) + 256)) * 8 - 2 */) - 1) * 2 + 1) : ((1 ? 0 : ((1 ? 0 : ans) + 256)) + 0)) / 256" is always false regardless of the values of its operands. This occurs as the second operand of "?:".
137 if (INT_MULTIPLY_OVERFLOW (ans, 256))
138 return -2;
139 ans *= 256;
140
141 if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt])))
142 return -2;
Here are the related macros from gnulib:
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
#define EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
#define TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
#define _GL_SIGNED_INT_MAXIMUM(e) \
(((_GL_INT_CONVERT (e, 1) << (TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
#define _GL_INT_MINIMUM(e) \
(EXPR_SIGNED (e) \
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_CONVERT (e, 0))
#define _GL_INT_MAXIMUM(e) \
(EXPR_SIGNED (e) \
? _GL_SIGNED_INT_MAXIMUM (e) \
: _GL_INT_NEGATE_CONVERT (e, 1))
#define INT_MULTIPLY_RANGE_OVERFLOW(a, b, min, max) \
((b) < 0 \
? ((a) < 0 \
? (a) < (max) / (b) \
: (b) == -1 \
? 0 \
: (min) / (b) < (a)) \
: (b) == 0 \
? 0 \
: ((a) < 0 \
? (a) < (min) / (b) \
: (max) / (b) < (a)))
# define _GL_MULTIPLY_OVERFLOW(a, b, min, max) \
(((min) == 0 && (((a) < 0 && 0 < (b)) || ((b) < 0 && 0 < (a)))) \
|| INT_MULTIPLY_RANGE_OVERFLOW (a, b, min, max))
#define _GL_BINARY_OP_OVERFLOW(a, b, op_result_overflow) \
op_result_overflow (a, b, \
_GL_INT_MINIMUM (_GL_INT_CONVERT (a, b)), \
_GL_INT_MAXIMUM (_GL_INT_CONVERT (a, b)))
#define INT_MULTIPLY_OVERFLOW(a, b) \
_GL_BINARY_OP_OVERFLOW (a, b, _GL_MULTIPLY_OVERFLOW)
The statement in question is the expanded '(a) < (min) / (b)' from
INT_MULTIPLY_RANGE_OVERFLOW.
'(a) < (min) / (b)'
=> '(a) < (_GL_INT_MINIMUM (_GL_INT_CONVERT (a, b))) / (b)'
=> '(ans) < (_GL_INT_MINIMUM (_GL_INT_CONVERT (ans, 256))) / (256)'
=> '(ans) < \
(EXPR_SIGNED (_GL_INT_CONVERT (ans, 256)) \
? ~ _GL_SIGNED_INT_MAXIMUM (_GL_INT_CONVERT (ans, 256)) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(_GL_INT_NEGATE_CONVERT (_GL_INT_CONVERT (ans, 256), 1) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (_GL_INT_CONVERT (ans, 256)) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : (_GL_INT_CONVERT (ans, 256))) - (1)) < 0) \
? ~ _GL_SIGNED_INT_MAXIMUM (_GL_INT_CONVERT (ans, 256)) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1)) < 0) \
? ~ (((_GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 1) << (TYPE_WIDTH (+ (_GL_INT_CONVERT (ans, 256))) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1)) < 0) \
? ~ ((((1 ? 0 : (_GL_INT_CONVERT (ans, 256))) + (1)) << (TYPE_WIDTH (+ (_GL_INT_CONVERT (ans, 256))) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1)) < 0) \
? ~ ((((1 ? 0 : ((1 ? 0 : (ans)) + (256))) + (1)) << (TYPE_WIDTH (+ (_GL_INT_CONVERT (ans, 256))) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1)) < 0) \
? ~ ((((1 ? 0 : ((1 ? 0 : (ans)) + (256))) + (1)) << ((sizeof (+ (_GL_INT_CONVERT (ans, 256))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1)) < 0) \
? ~ ((((1 ? 0 : ((1 ? 0 : (ans)) + (256))) + (1)) << ((sizeof (+ ((1 ? 0 : (ans)) + (1))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: _GL_INT_CONVERT (_GL_INT_CONVERT (ans, 256), 0)) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1)) < 0) \
? ~ ((((1 ? 0 : ((1 ? 0 : (ans)) + (256))) + (1)) << ((sizeof (+ ((1 ? 0 : (ans)) + (1))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: ((1 ? 0 : (_GL_INT_CONVERT (ans, 256))) + (0)) ) \
/ (256)'
=> '(ans) < \
(((1 ? 0 : ((1 ? 0 : (ans)) + (256))) - (1)) < 0) \
? ~ ((((1 ? 0 : ((1 ? 0 : (ans)) + (256))) + (1)) << ((sizeof (+ ((1 ? 0 : (ans)) + (1))) * CHAR_BIT) - 2)) - 1) * 2 + 1) \
: ((1 ? 0 : ((1 ? 0 : (ans)) + (256))) + (0)) ) \
/ (256)'
'_GL_INT_CONVERT(e, v)' returns a value with the common real type of 'e' and 'v' and
the value of 'v'. Since the common type of 'unsigned int ans' and '256' is
'unsigned int', '_GL_INT_CONVERT (ans, 256)' is '256U'.
'_GL_INT_MINIMUM (256U)' returns the minimum value of 'unsigned int', i.e. 0.
'(ans) < (_GL_INT_MINIMUM (_GL_INT_CONVERT (ans, 256))) / (256)' => '(ans) < 0 / (256)' => '(ans) < 0'
For 'unsigned int ans', the result is always false.
However, in 'INT_MULTIPLY_RANGE_OVERFLOW', 'a' is 'unsigned int ans' and 'b' is '256'.
We can skip the statements for 'b < 0' and 'b == 0' and reduce the macro to
(a) < 0 \
? (a) < (min) / (b) \
: (max) / (b) < (a))) \
Since '(ans) < 0' is false for 'unsigned int ans', the statement in question,
'(a) < (min) / (b)', is always skipped. Thus, the result of the statement doesn't
matter.
Daniel Axtens (4):
posix_wrap: tweaks in preparation for libtasn1
libtasn1: import libtasn1-4.19.0
libtasn1: compile into asn1 module
asn1_test: test module for libtasn1
Gary Lin (23):
libtasn1: disable code not needed in grub
libtasn1: replace strcat() with strcpy() in _asn1_str_cat()
libtasn1: replace strcat() with _asn1_str_cat()
libtasn1: adjust the header paths in libtasn1.h
libtasn1: Use grub_divmod64() for division
libtasn1: fix the potential buffer overrun
asn1_test: include asn1_test.h only
asn1_test: rename the main functions to the test names
asn1_test: remove 'verbose' and the unnecessary printf()
asn1_test: print the error messages with grub_printf()
asn1_test: return either 0 or 1 to reflect the results
asn1_test: use the grub-specific functions and types
libtasn1: Add the documentation
tss2: Add TPM2 buffer handling functions
tss2: Add TPM2 types and Marshal/Unmarshal functions
tss2: Add TPM2 Software Stack (TSS2) support
tpm2_key_protector: Support authorized policy
cryptodisk: wipe out the cached keys from protectors
diskfilter: look up cryptodisk devices first
tpm2_key_protector: Add grub-emu support
tests: Add tpm2_key_protector_test
cryptodisk: Document the '-P' option
docs: Document TPM2 key protector
Hernan Gatta (4):
key_protector: Add key protectors framework
key_protector: Add TPM2 Key Protector
cryptodisk: Support key protectors
util/grub-protect: Add new tool
Patrick Colp (2):
tpm2_key_protector: Implement NV index
cryptodisk: Fallback to passphrase
.gitignore | 2 +
Makefile.util.def | 39 +
autogen.sh | 32 +
configure.ac | 30 +
docs/grub-dev.texi | 35 +
docs/grub.texi | 512 +++-
docs/man/grub-protect.h2m | 4 +
grub-core/Makefile.am | 1 +
grub-core/Makefile.core.def | 60 +
grub-core/commands/tpm2_key_protector/args.c | 129 +
.../commands/tpm2_key_protector/module.c | 1238 ++++++++
grub-core/commands/tpm2_key_protector/tpm2.h | 36 +
.../commands/tpm2_key_protector/tpm2_args.h | 49 +
.../commands/tpm2_key_protector/tpm2key.asn | 49 +
.../commands/tpm2_key_protector/tpm2key.c | 499 ++++
.../commands/tpm2_key_protector/tpm2key.h | 87 +
.../tpm2_key_protector/tpm2key_asn1_tab.c | 63 +
grub-core/disk/cryptodisk.c | 268 +-
grub-core/disk/diskfilter.c | 31 +-
grub-core/disk/key_protector.c | 73 +
grub-core/kern/emu/main.c | 11 +-
grub-core/kern/emu/misc.c | 51 +
grub-core/lib/efi/tcg2.c | 143 +
...asn1-disable-code-not-needed-in-grub.patch | 320 +++
...-strcat-with-strcpy-in-_asn1_str_cat.patch | 32 +
...n1-replace-strcat-with-_asn1_str_cat.patch | 70 +
...djust-the-header-paths-in-libtasn1.h.patch | 38 +
...tasn1-Use-grub_divmod64-for-division.patch | 31 +
...sn1-fix-the-potential-buffer-overrun.patch | 36 +
...7-asn1_test-include-asn1_test.h-only.patch | 163 ++
...-the-main-functions-to-the-test-name.patch | 128 +
...e-verbose-and-the-unnecessary-printf.patch | 172 ++
...-the-error-messages-with-grub_printf.patch | 484 ++++
...-either-0-or-1-to-reflect-the-result.patch | 72 +
...he-grub-specific-functions-and-types.patch | 262 ++
grub-core/lib/libtasn1/COPYING | 16 +
grub-core/lib/libtasn1/README.md | 98 +
grub-core/lib/libtasn1/lib/coding.c | 1425 ++++++++++
grub-core/lib/libtasn1/lib/decoding.c | 2501 +++++++++++++++++
grub-core/lib/libtasn1/lib/element.c | 1109 ++++++++
grub-core/lib/libtasn1/lib/element.h | 42 +
grub-core/lib/libtasn1/lib/errors.c | 100 +
grub-core/lib/libtasn1/lib/gstr.c | 74 +
grub-core/lib/libtasn1/lib/gstr.h | 50 +
grub-core/lib/libtasn1/lib/int.h | 221 ++
grub-core/lib/libtasn1/lib/parser_aux.c | 1178 ++++++++
grub-core/lib/libtasn1/lib/parser_aux.h | 172 ++
grub-core/lib/libtasn1/lib/structure.c | 1225 ++++++++
grub-core/lib/libtasn1/lib/structure.h | 46 +
grub-core/lib/libtasn1/libtasn1.h | 643 +++++
.../tests/CVE-2018-1000654-1_asn1_tab.h | 32 +
.../tests/CVE-2018-1000654-2_asn1_tab.h | 36 +
.../lib/libtasn1/tests/CVE-2018-1000654.c | 72 +
grub-core/lib/libtasn1/tests/Test_overflow.c | 168 ++
grub-core/lib/libtasn1/tests/Test_simple.c | 226 ++
grub-core/lib/libtasn1/tests/Test_strings.c | 156 +
.../lib/libtasn1/tests/object-id-decoding.c | 121 +
.../lib/libtasn1/tests/object-id-encoding.c | 133 +
grub-core/lib/libtasn1/tests/octet-string.c | 230 ++
grub-core/lib/libtasn1/tests/reproducers.c | 90 +
grub-core/lib/libtasn1_wrap/wrap.c | 27 +
grub-core/lib/posix_wrap/c-ctype.h | 114 +
grub-core/lib/posix_wrap/limits.h | 1 +
grub-core/lib/posix_wrap/stdlib.h | 8 +
grub-core/lib/posix_wrap/string.h | 21 +
grub-core/lib/posix_wrap/sys/types.h | 1 +
grub-core/lib/tss2/buffer.c | 147 +
grub-core/lib/tss2/tcg2.h | 35 +
grub-core/lib/tss2/tcg2_emu.c | 54 +
grub-core/lib/tss2/tpm2_cmd.c | 1043 +++++++
grub-core/lib/tss2/tpm2_cmd.h | 157 ++
grub-core/lib/tss2/tss2.c | 21 +
grub-core/lib/tss2/tss2_buffer.h | 64 +
grub-core/lib/tss2/tss2_mu.c | 1174 ++++++++
grub-core/lib/tss2/tss2_mu.h | 397 +++
grub-core/lib/tss2/tss2_structs.h | 773 +++++
grub-core/lib/tss2/tss2_types.h | 404 +++
grub-core/tests/asn1/asn1_test.c | 50 +
grub-core/tests/asn1/asn1_test.h | 45 +
grub-core/tests/lib/functional_test.c | 1 +
include/grub/cryptodisk.h | 16 +
include/grub/emu/misc.h | 5 +
include/grub/key_protector.h | 47 +
tests/asn1_test.in | 11 +
tests/tpm2_key_protector_test.in | 389 +++
tests/util/grub-shell.in | 6 +-
util/grub-protect.c | 1394 +++++++++
87 files changed, 21742 insertions(+), 77 deletions(-)
create mode 100644 docs/man/grub-protect.h2m
create mode 100644 grub-core/commands/tpm2_key_protector/args.c
create mode 100644 grub-core/commands/tpm2_key_protector/module.c
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2.h
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2_args.h
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.asn
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.c
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.h
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c
create mode 100644 grub-core/disk/key_protector.c
create mode 100644 grub-core/lib/efi/tcg2.c
create mode 100644 grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch
create mode 100644 grub-core/lib/libtasn1-patches/0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch
create mode 100644 grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch
create mode 100644 grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch
create mode 100644 grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch
create mode 100644 grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch
create mode 100644 grub-core/lib/libtasn1-patches/0007-asn1_test-include-asn1_test.h-only.patch
create mode 100644 grub-core/lib/libtasn1-patches/0008-asn1_test-rename-the-main-functions-to-the-test-name.patch
create mode 100644 grub-core/lib/libtasn1-patches/0009-asn1_test-remove-verbose-and-the-unnecessary-printf.patch
create mode 100644 grub-core/lib/libtasn1-patches/0010-asn1_test-print-the-error-messages-with-grub_printf.patch
create mode 100644 grub-core/lib/libtasn1-patches/0011-asn1_test-return-either-0-or-1-to-reflect-the-result.patch
create mode 100644 grub-core/lib/libtasn1-patches/0012-asn1_test-use-the-grub-specific-functions-and-types.patch
create mode 100644 grub-core/lib/libtasn1/COPYING
create mode 100644 grub-core/lib/libtasn1/README.md
create mode 100644 grub-core/lib/libtasn1/lib/coding.c
create mode 100644 grub-core/lib/libtasn1/lib/decoding.c
create mode 100644 grub-core/lib/libtasn1/lib/element.c
create mode 100644 grub-core/lib/libtasn1/lib/element.h
create mode 100644 grub-core/lib/libtasn1/lib/errors.c
create mode 100644 grub-core/lib/libtasn1/lib/gstr.c
create mode 100644 grub-core/lib/libtasn1/lib/gstr.h
create mode 100644 grub-core/lib/libtasn1/lib/int.h
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h
create mode 100644 grub-core/lib/libtasn1/lib/structure.c
create mode 100644 grub-core/lib/libtasn1/lib/structure.h
create mode 100644 grub-core/lib/libtasn1/libtasn1.h
create mode 100644 grub-core/lib/libtasn1/tests/CVE-2018-1000654-1_asn1_tab.h
create mode 100644 grub-core/lib/libtasn1/tests/CVE-2018-1000654-2_asn1_tab.h
create mode 100644 grub-core/lib/libtasn1/tests/CVE-2018-1000654.c
create mode 100644 grub-core/lib/libtasn1/tests/Test_overflow.c
create mode 100644 grub-core/lib/libtasn1/tests/Test_simple.c
create mode 100644 grub-core/lib/libtasn1/tests/Test_strings.c
create mode 100644 grub-core/lib/libtasn1/tests/object-id-decoding.c
create mode 100644 grub-core/lib/libtasn1/tests/object-id-encoding.c
create mode 100644 grub-core/lib/libtasn1/tests/octet-string.c
create mode 100644 grub-core/lib/libtasn1/tests/reproducers.c
create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
create mode 100644 grub-core/lib/posix_wrap/c-ctype.h
create mode 100644 grub-core/lib/tss2/buffer.c
create mode 100644 grub-core/lib/tss2/tcg2.h
create mode 100644 grub-core/lib/tss2/tcg2_emu.c
create mode 100644 grub-core/lib/tss2/tpm2_cmd.c
create mode 100644 grub-core/lib/tss2/tpm2_cmd.h
create mode 100644 grub-core/lib/tss2/tss2.c
create mode 100644 grub-core/lib/tss2/tss2_buffer.h
create mode 100644 grub-core/lib/tss2/tss2_mu.c
create mode 100644 grub-core/lib/tss2/tss2_mu.h
create mode 100644 grub-core/lib/tss2/tss2_structs.h
create mode 100644 grub-core/lib/tss2/tss2_types.h
create mode 100644 grub-core/tests/asn1/asn1_test.c
create mode 100644 grub-core/tests/asn1/asn1_test.h
create mode 100644 include/grub/key_protector.h
create mode 100644 tests/asn1_test.in
create mode 100644 tests/tpm2_key_protector_test.in
create mode 100644 util/grub-protect.c
Range-diff against v18:
1: 77d52a5b7 = 1: 7ddef18d2 posix_wrap: tweaks in preparation for libtasn1
2: 931fccd49 = 2: f27ad35a7 libtasn1: import libtasn1-4.19.0
3: 1ca207217 ! 3: 86f8e472e libtasn1: disable code not needed in grub
@@ Commit message
## grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch (new) ##
@@
-+From 6b61d48782dc67bed72af70aa5db5b9cb1b4f1d0 Mon Sep 17 00:00:00 2001
++From b927f1b24fe10c57edc9711ff4baa12b013ce351 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 1 May 2020 17:12:23 +1000
-+Subject: [PATCH 1/6] libtasn1: disable code not needed in grub
++Subject: [PATCH 01/12] libtasn1: disable code not needed in grub
+
+We don't expect to be able to write ASN.1, only read it,
+so we can disable some code.
@@ grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.pat
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
++Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/lib/libtasn1-grub/lib/coding.c | 12 ++++++++++--
+ grub-core/lib/libtasn1-grub/lib/decoding.c | 2 ++
-: --------- > 4: 455cee6e0 libtasn1: replace strcat() with strcpy() in _asn1_str_cat()
4: bf48cf8f8 ! 5: 6c2df83bd libtasn1: use bound-checked _asn1_str_cat()
@@ Metadata
Author: Gary Lin <glin@suse.com>
## Commit message ##
- libtasn1: use bound-checked _asn1_str_cat()
+ libtasn1: replace strcat() with _asn1_str_cat()
- Remove _asn1_strcat() and replace strcat() with the bound-checked
- _asn1_str_cat() except the one inside _asn1_str_cat(). That strcat
- is replaced with strcpy.
+ strcat() is not available in GRUB. This commit replaces strcat() and
+ _asn1_strcat() with the bounds-checking _asn1_str_cat().
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
- ## grub-core/lib/libtasn1-patches/0002-libtasn1-use-bound-checked-_asn1_str_cat.patch (new) ##
+ ## grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch (new) ##
@@
-+From d87d8e78371e3afbdd876193295ab9e3f60c140b Mon Sep 17 00:00:00 2001
++From 8aa07d427966fbb560871a0a87e0af876920002c Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
-+Date: Tue, 25 Jun 2024 16:27:57 +0800
-+Subject: [PATCH 2/6] libtasn1: use bound-checked _asn1_str_cat()
++Date: Tue, 20 Aug 2024 16:26:45 +0800
++Subject: [PATCH 03/12] libtasn1: replace strcat() with _asn1_str_cat()
+
-+Remove _asn1_strcat() and replace strcat() with the bound-checked
-+_asn1_str_cat() except the one inside _asn1_str_cat(). That strcat
-+is replaced with strcpy.
++strcat() is not available in GRUB. This commit replaces strcat() and
++_asn1_strcat() with the bounds-checking _asn1_str_cat().
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/lib/libtasn1-grub/lib/decoding.c | 8 ++++----
+ grub-core/lib/libtasn1-grub/lib/element.c | 2 +-
-+ grub-core/lib/libtasn1-grub/lib/gstr.c | 2 +-
+ grub-core/lib/libtasn1-grub/lib/int.h | 1 -
-+ 4 files changed, 6 insertions(+), 7 deletions(-)
++ 3 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1-grub/lib/decoding.c b/grub-core/lib/libtasn1-grub/lib/decoding.c
+index bf9cb13ac..51859fe36 100644
@@ -688,7 +688,7 @@ asn1_write_value (asn1_node node_root, const char *name,
+ }
+
+ /**
-+diff --git a/grub-core/lib/libtasn1-grub/lib/gstr.c b/grub-core/lib/libtasn1-grub/lib/gstr.c
-+index eef419554..a9c16f5d3 100644
-+--- a/grub-core/lib/libtasn1-grub/lib/gstr.c
-++++ b/grub-core/lib/libtasn1-grub/lib/gstr.c
-+@@ -36,7 +36,7 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
-+
-+ if (dest_tot_size - dest_size > str_size)
-+ {
-+- strcat (dest, src);
-++ strcpy (dest + dest_size, src);
-+ }
-+ else
-+ {
+diff --git a/grub-core/lib/libtasn1-grub/lib/int.h b/grub-core/lib/libtasn1-grub/lib/int.h
+index d94d51c8c..cadd80df6 100644
+--- a/grub-core/lib/libtasn1-grub/lib/int.h
5: 0f93bcdf5 ! 6: 626894626 libtasn1: adjust the header paths in libtasn1.h
@@ Metadata
## Commit message ##
libtasn1: adjust the header paths in libtasn1.h
- Use the grub headers instead of the standard POSIX headers.
+ Since libtasn1.h is the header to be included by users, including the
+ standard POSIX headers in libtasn1.h would force the user to add the
+ CFLAGS/CPPFLAGS for the POSIX headers.
+
+ This commit adjusts the header paths to use the grub headers instead of
+ the standard POSIX headers, so that users only need to include
+ libtasn1.h to use libtasn1 functions.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
- ## grub-core/lib/libtasn1-patches/0003-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch (new) ##
+ ## grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch (new) ##
@@
-+From da7ac4d6dff8876fc18f006de3c72da3c93833f5 Mon Sep 17 00:00:00 2001
++From 3ea2376db98e99a4461411fc476850de33822999 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Tue, 25 Jun 2024 16:30:40 +0800
-+Subject: [PATCH 3/6] libtasn1: adjust the header paths in libtasn1.h
++Subject: [PATCH 04/12] libtasn1: adjust the header paths in libtasn1.h
++
++Since libtasn1.h is the header to be included by users, including the
++standard POSIX headers in libtasn1.h would force the user to add the
++CFLAGS/CPPFLAGS for the POSIX headers.
+
-+Use the grub headers instead of the standard POSIX headers.
++This commit adjusts the header paths to use the grub headers instead of
++the standard POSIX headers, so that users only need to include
++libtasn1.h to use libtasn1 functions.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
6: ab1fdab6f ! 7: 9805bc603 libtasn1: Use grub_divmod64() for division
@@ Metadata
## Commit message ##
libtasn1: Use grub_divmod64() for division
- Replace a 64 bit division with a call to grub_divmod64, preventing
- creation of __udivdi3 calls on 32 bit platforms.
+ Replace a 64-bit division with a call to grub_divmod64(), preventing
+ creation of __udivdi3() calls on 32-bit platforms.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
- ## grub-core/lib/libtasn1-patches/0004-libtasn1-Use-grub_divmod64-for-division.patch (new) ##
+ ## grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch (new) ##
@@
-+From 52ad4fb6a023f27fdcea490d8e4956ce3957b1f9 Mon Sep 17 00:00:00 2001
++From f4d086cc829544a33fd6fd705538cd8d820d6c40 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Tue, 25 Jun 2024 16:32:50 +0800
-+Subject: [PATCH 4/6] libtasn1: Use grub_divmod64() for division
++Subject: [PATCH 05/12] libtasn1: Use grub_divmod64() for division
+
-+Replace a 64 bit division with a call to grub_divmod64, preventing
-+creation of __udivdi3 calls on 32 bit platforms.
++Replace a 64-bit division with a call to grub_divmod64(), preventing
++creation of __udivdi3() calls on 32-bit platforms.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
++Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/lib/libtasn1-grub/lib/parser_aux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
7: caa413fd4 ! 8: 15b0caaaf libtasn1: fix the potential buffer overrun
@@ Commit message
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
- ## grub-core/lib/libtasn1-patches/0005-libtasn1-fix-the-potential-buffer-overrun.patch (new) ##
+ ## grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch (new) ##
@@
-+From 38cc5e33cf89ed5d3152923fbedd9869bf566bb5 Mon Sep 17 00:00:00 2001
++From 66f5485a9b4ea02f7d2796c5f245fcbf7c88b390 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Mon, 8 Apr 2024 14:57:21 +0800
-+Subject: [PATCH 5/6] libtasn1: fix the potential buffer overrun
++Subject: [PATCH 06/12] libtasn1: fix the potential buffer overrun
+
+In _asn1_tag_der(), the first while loop for the long form may end up
+with a 'k' value with 'ASN1_MAX_TAG_SIZE' and cause the buffer overrun
@@ grub-core/lib/libtasn1-patches/0005-libtasn1-fix-the-potential-buffer-overrun.pa
+libtasn1 issue: https://gitlab.com/gnutls/libtasn1/-/issues/49
+
+Signed-off-by: Gary Lin <glin@suse.com>
++Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/lib/libtasn1-grub/lib/coding.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
8: 28045abf2 < -: --------- asn1_test: changes for grub compatibility
-: --------- > 9: 96da6bf0d asn1_test: include asn1_test.h only
-: --------- > 10: e00a23d87 asn1_test: rename the main functions to the test names
-: --------- > 11: 6e91722f6 asn1_test: remove 'verbose' and the unnecessary printf()
-: --------- > 12: c717d8585 asn1_test: print the error messages with grub_printf()
-: --------- > 13: a1a1f32a6 asn1_test: return either 0 or 1 to reflect the results
-: --------- > 14: 8e33e1600 asn1_test: use the grub-specific functions and types
9: 87b0b3860 ! 15: 9731f42c9 libtasn1: compile into asn1 module
@@ autogen.sh: for x in mpi-asm-defs.h mpih-add1.c mpih-sub1.c mpih-mul1.c mpih-mul
+
+for patch in \
+ 0001-libtasn1-disable-code-not-needed-in-grub.patch \
-+ 0002-libtasn1-use-bound-checked-_asn1_str_cat.patch \
-+ 0003-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch \
-+ 0004-libtasn1-Use-grub_divmod64-for-division.patch \
-+ 0005-libtasn1-fix-the-potential-buffer-overrun.patch ; do
++ 0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch \
++ 0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch \
++ 0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch \
++ 0005-libtasn1-Use-grub_divmod64-for-division.patch \
++ 0006-libtasn1-fix-the-potential-buffer-overrun.patch ; do
+ patch -p1 -i grub-core/lib/libtasn1-patches/$patch
+done
+
@@ grub-core/lib/libtasn1_wrap/wrap.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2020 IBM Corporation
++ * Copyright (C) 2024 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
10: 6e39c7766 ! 16: 6fd2a949c asn1_test: test module for libtasn1
@@ Metadata
## Commit message ##
asn1_test: test module for libtasn1
- Import tests from libtasn1 that don't use functionality we don't
- import. This test module is integrated into functional_test so that the
+ Import tests from libtasn1 that use functionality we import.
+ This test module is integrated into functional_test so that the
user can run the test in grub shell.
This doesn't test the full decoder but that will be exercised in
@@ Commit message
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
## Makefile.util.def ##
@@ Makefile.util.def: script = {
@@ autogen.sh: mkdir -p grub-core/lib/libtasn1-grub/lib
+
for patch in \
0001-libtasn1-disable-code-not-needed-in-grub.patch \
- 0002-libtasn1-use-bound-checked-_asn1_str_cat.patch \
- 0003-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch \
- 0004-libtasn1-Use-grub_divmod64-for-division.patch \
-- 0005-libtasn1-fix-the-potential-buffer-overrun.patch ; do
-+ 0005-libtasn1-fix-the-potential-buffer-overrun.patch \
-+ 0006-asn1_test-changes-for-grub-compatibility.patch ; do
+ 0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch \
+ 0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch \
+ 0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch \
+ 0005-libtasn1-Use-grub_divmod64-for-division.patch \
+- 0006-libtasn1-fix-the-potential-buffer-overrun.patch ; do
++ 0006-libtasn1-fix-the-potential-buffer-overrun.patch \
++ 0007-asn1_test-include-asn1_test.h-only.patch \
++ 0008-asn1_test-rename-the-main-functions-to-the-test-name.patch \
++ 0009-asn1_test-remove-verbose-and-the-unnecessary-printf.patch \
++ 0010-asn1_test-print-the-error-messages-with-grub_printf.patch \
++ 0011-asn1_test-return-either-0-or-1-to-reflect-the-result.patch \
++ 0012-asn1_test-use-the-grub-specific-functions-and-types.patch ; do
patch -p1 -i grub-core/lib/libtasn1-patches/$patch
done
@@ grub-core/tests/asn1/asn1_test.c (new)
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2020 IBM Corporation
++ * Copyright (C) 2024 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
@@ grub-core/tests/asn1/asn1_test.h (new)
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2020 IBM Corporation
++ * Copyright (C) 2024 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
@@ grub-core/tests/asn1/asn1_test.h (new)
+#include <grub/misc.h>
+#include <grub/types.h>
+
-+int test_CVE_2018_1000654 (void);
++extern int test_CVE_2018_1000654 (void);
+
-+int test_object_id_encoding (void);
++extern int test_object_id_encoding (void);
+
-+int test_object_id_decoding (void);
++extern int test_object_id_decoding (void);
+
-+int test_octet_string (void);
++extern int test_octet_string (void);
+
-+int test_overflow (void);
++extern int test_overflow (void);
+
-+int test_reproducers (void);
++extern int test_reproducers (void);
+
-+int test_simple (void);
++extern int test_simple (void);
+
-+int test_strings (void);
++extern int test_strings (void);
+
+#endif
11: 5a8b24309 ! 17: a7ae94e27 libtasn1: Add the documentation
@@ Commit message
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
## docs/grub-dev.texi ##
@@ docs/grub-dev.texi: to update it.
12: 3059a8df6 ! 18: 53342acde key_protector: Add key protectors framework
@@ grub-core/disk/key_protector.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/disk/key_protector.c (new)
+grub_err_t
+grub_key_protector_register (struct grub_key_protector *protector)
+{
-+ if (protector == NULL || protector->name == NULL || grub_strlen (protector->name) == 0)
-+ return GRUB_ERR_BAD_ARGUMENT;
++ if (protector == NULL || protector->name == NULL || protector->name[0] == '\0')
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector for registration");
+
-+ if (grub_key_protectors &&
-+ grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors),
-+ protector->name))
-+ return GRUB_ERR_BAD_ARGUMENT;
++ if (grub_key_protectors != NULL &&
++ grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), protector->name) != NULL)
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Key protector '%s' already registered", protector->name);
+
-+ grub_list_push (GRUB_AS_LIST_P (&grub_key_protectors),
-+ GRUB_AS_LIST (protector));
++ grub_list_push (GRUB_AS_LIST_P (&grub_key_protectors), GRUB_AS_LIST (protector));
+
+ return GRUB_ERR_NONE;
+}
@@ grub-core/disk/key_protector.c (new)
+grub_key_protector_unregister (struct grub_key_protector *protector)
+{
+ if (protector == NULL)
-+ return GRUB_ERR_BAD_ARGUMENT;
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector for unregistration");
+
+ grub_list_remove (GRUB_AS_LIST (protector));
+
@@ grub-core/disk/key_protector.c (new)
+ struct grub_key_protector *kp = NULL;
+
+ if (grub_key_protectors == NULL)
-+ return GRUB_ERR_OUT_OF_RANGE;
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "No key protector registered");
+
-+ if (protector == NULL || grub_strlen (protector) == 0)
-+ return GRUB_ERR_BAD_ARGUMENT;
++ if (protector == NULL || protector[0] == '\0')
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector");
+
-+ kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors),
-+ protector);
++ kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), protector);
+ if (kp == NULL)
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
-+ N_("A key protector with name '%s' could not be found. "
-+ "Is the name spelled correctly and is the "
-+ "corresponding module loaded?"), protector);
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Key protector '%s' not found", protector);
+
+ return kp->recover_key (key, key_size);
+}
@@ include/grub/key_protector.h (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
13: 584346494 ! 19: db99647d5 tss2: Add TPM2 buffer handling functions
@@ Commit message
Cc: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
## grub-core/lib/tss2/buffer.c (new) ##
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/lib/tss2/buffer.c (new)
+}
+
+void
-+grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void* data,
-+ grub_size_t size)
++grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void *data, grub_size_t size)
+{
+ grub_uint32_t r = buffer->cap - buffer->size;
+
@@ grub-core/lib/tss2/buffer.c (new)
+ return;
+ }
+
-+ grub_memcpy (&buffer->data[buffer->size], (void*) data, size);
++ grub_memcpy (&buffer->data[buffer->size], (void *) data, size);
+ buffer->size += size;
+}
+
+void
+grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value)
+{
-+ grub_tpm2_buffer_pack (buffer, (const char*) &value, sizeof (value));
++ grub_tpm2_buffer_pack (buffer, (const void *) &value, sizeof (value));
+}
+
+void
@@ grub-core/lib/tss2/buffer.c (new)
+{
+ grub_uint16_t tmp = grub_cpu_to_be16 (value);
+
-+ grub_tpm2_buffer_pack (buffer, (const char*) &tmp, sizeof (tmp));
++ grub_tpm2_buffer_pack (buffer, (const void *) &tmp, sizeof (tmp));
+}
+
+void
@@ grub-core/lib/tss2/buffer.c (new)
+{
+ grub_uint32_t tmp = grub_cpu_to_be32 (value);
+
-+ grub_tpm2_buffer_pack (buffer, (const char*) &tmp, sizeof (tmp));
++ grub_tpm2_buffer_pack (buffer, (const void *) &tmp, sizeof (tmp));
+}
+
+void
-+grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void* data,
-+ grub_size_t size)
++grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void *data, grub_size_t size)
+{
+ grub_uint32_t r = buffer->size - buffer->offset;
+
@@ grub-core/lib/tss2/buffer.c (new)
+}
+
+void
-+grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t* value)
++grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t *value)
+{
+ grub_uint32_t r = buffer->size - buffer->offset;
+
@@ grub-core/lib/tss2/buffer.c (new)
+}
+
+void
-+grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t* value)
++grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t *value)
+{
+ grub_uint16_t tmp;
+ grub_uint32_t r = buffer->size - buffer->offset;
@@ grub-core/lib/tss2/buffer.c (new)
+}
+
+void
-+grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t* value)
++grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t *value)
+{
+ grub_uint32_t tmp;
+ grub_uint32_t r = buffer->size - buffer->offset;
@@ grub-core/lib/tss2/tss2_buffer.h (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/lib/tss2/tss2_buffer.h (new)
+ grub_size_t size;
+ grub_size_t offset;
+ grub_size_t cap;
-+ grub_uint8_t error;
++ bool error;
+};
+typedef struct grub_tpm2_buffer *grub_tpm2_buffer_t;
+
-+void
++extern void
+grub_tpm2_buffer_init (grub_tpm2_buffer_t buffer);
+
-+void
-+grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void* data,
-+ grub_size_t size);
++extern void
++grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void *data, grub_size_t size);
+
-+void
++extern void
+grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value);
+
-+void
++extern void
+grub_tpm2_buffer_pack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t value);
+
-+void
++extern void
+grub_tpm2_buffer_pack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t value);
+
-+void
-+grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void* data,
-+ grub_size_t size);
++extern void
++grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void *data, grub_size_t size);
+
-+void
-+grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t* value);
++extern void
++grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t *value);
+
-+void
-+grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t* value);
++extern void
++grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t *value);
+
-+void
-+grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t* value);
++extern void
++grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t *value);
+
+#endif /* ! GRUB_TPM2_BUFFER_HEADER */
14: c2c071d9c < -: --------- tss2: Add TPM2 types and Marshal/Unmarshal functions
-: --------- > 20: a5e494bb2 tss2: Add TPM2 types and Marshal/Unmarshal functions
15: c3161e49b ! 21: 47cc29d2d tss2: Add TPM2 Software Stack (TSS2) support
@@ Commit message
necessary to, first, possess knowledge of the various TPM structures, and,
second, of the TPM wire protocol itself.
- As such, this patch includes implementations of various TPM2_* functions
+ As such, this patch includes implementations of various grub_tpm2_* functions
(inventoried below), and logic to write and read command and response
buffers, respectively, using the TPM wire protocol.
- Functions: TPM2_Create, TPM2_CreatePrimary, TPM2_EvictControl,
- TPM2_FlushContext, TPM2_Load, TPM2_PCR_Read, TPM2_PolicyGetDigest,
- TPM2_PolicyPCR, TPM2_ReadPublic, TPM2_StartAuthSession, TPM2_Unseal,
- TPM2_LoadExternal, TPM2_Hash, TPM2_VerifySignature,
- TPM2_PolicyAuthorize, TPM2_TestParms
+ Functions:
+ * grub_tpm2_create()
+ * grub_tpm2_createprimary()
+ * grub_tpm2_evictcontrol()
+ * grub_tpm2_flushcontext()
+ * grub_tpm2_load()
+ * grub_tpm2_pcr_read()
+ * grub_tpm2_policygetdigest()
+ * grub_tpm2_policypcr()
+ * grub_tpm2_readpublic()
+ * grub_tpm2_startauthsession()
+ * grub_tpm2_unseal()
+ * grub_tpm2_loadexternal()
+ * grub_tpm2_hash()
+ * grub_tpm2_verifysignature()
+ * grub_tpm2_policyauthorize()
+ * grub_tpm2_testparms()
Cc: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
## grub-core/Makefile.core.def ##
@@ grub-core/Makefile.core.def: module = {
@@ grub-core/lib/efi/tcg2.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/lib/efi/tcg2.c (new)
+#include <tcg2.h>
+
+static grub_err_t
-+grub_tcg2_get_caps (grub_efi_tpm2_protocol_t *protocol, int *tpm2,
-+ grub_size_t *max_output_size)
++tcg2_get_caps (grub_efi_tpm2_protocol_t *protocol, int *tpm2, grub_size_t *max_output_size)
+{
+ grub_efi_status_t status;
-+ static int has_caps = 0;
++ static bool has_caps = 0;
+ static EFI_TCG2_BOOT_SERVICE_CAPABILITY caps =
+ {
+ .Size = (grub_uint8_t) sizeof (caps)
@@ grub-core/lib/efi/tcg2.c (new)
+}
+
+static grub_err_t
-+grub_tcg2_get_protocol (grub_efi_tpm2_protocol_t **protocol)
++tcg2_get_protocol (grub_efi_tpm2_protocol_t **protocol)
+{
+ static grub_guid_t tpm2_guid = EFI_TPM2_GUID;
+ static grub_efi_tpm2_protocol_t *tpm2_protocol = NULL;
@@ grub-core/lib/efi/tcg2.c (new)
+ if (tpm2_protocol == NULL)
+ goto exit;
+
-+ err = grub_tcg2_get_caps (tpm2_protocol, &tpm2, NULL);
++ err = tcg2_get_caps (tpm2_protocol, &tpm2, NULL);
+ if (err != GRUB_ERR_NONE || tpm2 == 0)
+ goto exit;
+
@@ grub-core/lib/efi/tcg2.c (new)
+ if (size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
-+ err = grub_tcg2_get_protocol (&protocol);
++ err = tcg2_get_protocol (&protocol);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
-+ err = grub_tcg2_get_caps (protocol, NULL, &max);
++ err = tcg2_get_caps (protocol, NULL, &max);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
@@ grub-core/lib/efi/tcg2.c (new)
+ output_size == 0 || output == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
-+ err = grub_tcg2_get_protocol (&protocol);
++ err = tcg2_get_protocol (&protocol);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
@@ grub-core/lib/tss2/tcg2.h (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/lib/tss2/tcg2.h (new)
+#include <grub/err.h>
+#include <grub/types.h>
+
-+grub_err_t
++extern grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size);
+
-+grub_err_t
++extern grub_err_t
+grub_tcg2_submit_command (grub_size_t input_size,
+ grub_uint8_t *input,
+ grub_size_t output_size,
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+#include <tcg2.h>
+#include <tpm2_cmd.h>
+
-+static TPM_RC
-+grub_tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG tag,
-+ const TPM_CC commandCode,
-+ TPM_RC *responseCode,
-+ const struct grub_tpm2_buffer *in,
-+ struct grub_tpm2_buffer *out)
++static TPM_RC_t
++tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG_t tag,
++ const TPM_CC_t commandCode,
++ TPM_RC_t *responseCode,
++ const struct grub_tpm2_buffer *in,
++ struct grub_tpm2_buffer *out)
+{
+ grub_err_t err;
+ struct grub_tpm2_buffer buf;
-+ TPMI_ST_COMMAND_TAG tag_out;
++ TPMI_ST_COMMAND_TAG_t tag_out;
+ grub_uint32_t command_size;
+ grub_size_t max_output_size;
+
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ max_output_size = out->cap - 1;
+
+ /* Submit */
-+ err = grub_tcg2_submit_command (buf.size, buf.data, max_output_size,
-+ out->data);
++ err = grub_tcg2_submit_command (buf.size, buf.data, max_output_size, out->data);
+ if (err != GRUB_ERR_NONE)
+ return TPM_RC_FAILURE;
+
+ /* Unmarshal */
-+ out->size = sizeof (grub_uint16_t) + sizeof (grub_uint32_t) +
-+ sizeof (grub_uint32_t);
++ out->size = sizeof (grub_uint16_t) + sizeof (grub_uint32_t) + sizeof (grub_uint32_t);
+ grub_tpm2_buffer_unpack_u16 (out, &tag_out);
+ grub_tpm2_buffer_unpack_u32 (out, &command_size);
+ grub_tpm2_buffer_unpack_u32 (out, responseCode);
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+static TPM_RC
-+grub_tpm2_submit_command (const TPMI_ST_COMMAND_TAG tag,
-+ const TPM_CC commandCode,
-+ TPM_RC *responseCode,
-+ const struct grub_tpm2_buffer *in,
-+ struct grub_tpm2_buffer *out)
++static TPM_RC_t
++tpm2_submit_command (const TPMI_ST_COMMAND_TAG_t tag,
++ const TPM_CC_t commandCode,
++ TPM_RC_t *responseCode,
++ const struct grub_tpm2_buffer *in,
++ struct grub_tpm2_buffer *out)
+{
-+ TPM_RC err;
++ TPM_RC_t err;
+ int retry_cnt = 0;
+
+ /* Catch TPM_RC_RETRY and send the command again */
+ do {
-+ err = grub_tpm2_submit_command_real (tag, commandCode, responseCode,
-+ in, out);
++ err = tpm2_submit_command_real (tag, commandCode, responseCode, in, out);
+ if (*responseCode != TPM_RC_RETRY)
+ break;
+
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return err;
+}
+
-+TPM_RC
-+TPM2_CreatePrimary (const TPMI_RH_HIERARCHY primaryHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_SENSITIVE_CREATE *inSensitive,
-+ const TPM2B_PUBLIC *inPublic,
-+ const TPM2B_DATA *outsideInfo,
-+ const TPML_PCR_SELECTION *creationPCR,
-+ TPM_HANDLE *objectHandle,
-+ TPM2B_PUBLIC *outPublic,
-+ TPM2B_CREATION_DATA *creationData,
-+ TPM2B_DIGEST *creationHash,
-+ TPMT_TK_CREATION *creationTicket,
-+ TPM2B_NAME *name,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_createprimary (const TPMI_RH_HIERARCHY_t primaryHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
++ const TPM2B_PUBLIC_t *inPublic,
++ const TPM2B_DATA_t *outsideInfo,
++ const TPML_PCR_SELECTION_t *creationPCR,
++ TPM_HANDLE_t *objectHandle,
++ TPM2B_PUBLIC_t *outPublic,
++ TPM2B_CREATION_DATA_t *creationData,
++ TPM2B_DIGEST_t *creationHash,
++ TPMT_TK_CREATION_t *creationTicket,
++ TPM2B_NAME_t *name,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPM_HANDLE objectHandleTmp;
-+ TPM2B_PUBLIC outPublicTmp;
-+ TPM2B_CREATION_DATA creationDataTmp;
-+ TPM2B_DIGEST creationHashTmp;
-+ TPMT_TK_CREATION creationTicketTmp;
-+ TPM2B_NAME nameTmp;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPM_HANDLE_t objectHandleTmp;
++ TPM2B_PUBLIC_t outPublicTmp;
++ TPM2B_CREATION_DATA_t creationDataTmp;
++ TPM2B_DIGEST_t creationHashTmp;
++ TPMT_TK_CREATION_t creationTicketTmp;
++ TPM2B_NAME_t nameTmp;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ if (inSensitive == NULL || inPublic == NULL || outsideInfo == NULL ||
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_CreatePrimary, &responseCode, &in,
-+ &out);
++ rc = tpm2_submit_command (tag, TPM_CC_CreatePrimary, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_StartAuthSession (const TPMI_DH_OBJECT tpmKey,
-+ const TPMI_DH_ENTITY bind,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_NONCE *nonceCaller,
-+ const TPM2B_ENCRYPTED_SECRET *encryptedSalt,
-+ const TPM_SE sessionType,
-+ const TPMT_SYM_DEF *symmetric,
-+ const TPMI_ALG_HASH authHash,
-+ TPMI_SH_AUTH_SESSION *sessionHandle,
-+ TPM2B_NONCE *nonceTpm,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_startauthsession (const TPMI_DH_OBJECT_t tpmKey,
++ const TPMI_DH_ENTITY_t bind,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_NONCE_t *nonceCaller,
++ const TPM2B_ENCRYPTED_SECRET_t *encryptedSalt,
++ const TPM_SE_t sessionType,
++ const TPMT_SYM_DEF_t *symmetric,
++ const TPMI_ALG_HASH_t authHash,
++ TPMI_SH_AUTH_SESSION_t *sessionHandle,
++ TPM2B_NONCE_t *nonceTpm,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMI_SH_AUTH_SESSION sessionHandleTmp;
-+ TPM2B_NONCE nonceTpmTmp;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPMI_SH_AUTH_SESSION_t sessionHandleTmp;
++ TPM2B_NONCE_t nonceTpmTmp;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (nonceCaller == NULL || symmetric == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_StartAuthSession, &responseCode,
++ rc = tpm2_submit_command (tag, TPM_CC_StartAuthSession, &responseCode,
+ &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_PolicyPCR (const TPMI_SH_POLICY policySessions,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_DIGEST *pcrDigest,
-+ const TPML_PCR_SELECTION *pcrs,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_policypcr (const TPMI_SH_POLICY_t policySessions,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_DIGEST_t *pcrDigest,
++ const TPML_PCR_SELECTION_t *pcrs,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (pcrs == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyPCR, &responseCode, &in,
-+ &out);
++ rc = tpm2_submit_command (tag, TPM_CC_PolicyPCR, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_ReadPublic (const TPMI_DH_OBJECT objectHandle,
-+ const TPMS_AUTH_COMMAND* authCommand,
-+ TPM2B_PUBLIC *outPublic)
++TPM_RC_t
++grub_tpm2_readpublic (const TPMI_DH_OBJECT_t objectHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ TPM2B_PUBLIC_t *outPublic)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ /* Marshal */
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_ReadPublic, &responseCode, &in,
-+ &out);
++ rc = tpm2_submit_command (tag, TPM_CC_ReadPublic, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_Load (const TPMI_DH_OBJECT parent_handle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_PRIVATE *inPrivate,
-+ const TPM2B_PUBLIC *inPublic,
-+ TPM_HANDLE *objectHandle,
-+ TPM2B_NAME *name,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_load (const TPMI_DH_OBJECT_t parent_handle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_PRIVATE_t *inPrivate,
++ const TPM2B_PUBLIC_t *inPublic,
++ TPM_HANDLE_t *objectHandle,
++ TPM2B_NAME_t *name,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPM_HANDLE objectHandleTmp;
-+ TPM2B_NAME nameTmp;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPM_HANDLE_t objectHandleTmp;
++ TPM2B_NAME_t nameTmp;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (inPrivate == NULL || inPublic == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_Load, &responseCode, &in, &out);
++ rc = tpm2_submit_command (tag, TPM_CC_Load, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_LoadExternal (const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_SENSITIVE *inPrivate,
-+ const TPM2B_PUBLIC *inPublic,
-+ const TPMI_RH_HIERARCHY hierarchy,
-+ TPM_HANDLE *objectHandle,
-+ TPM2B_NAME *name,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_loadexternal (const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_SENSITIVE_t *inPrivate,
++ const TPM2B_PUBLIC_t *inPublic,
++ const TPMI_RH_HIERARCHY_t hierarchy,
++ TPM_HANDLE_t *objectHandle,
++ TPM2B_NAME_t *name,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPM_HANDLE objectHandleTmp;
-+ TPM2B_NAME nameTmp;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPM_HANDLE_t objectHandleTmp;
++ TPM2B_NAME_t nameTmp;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (inPublic == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_LoadExternal, &responseCode, &in, &out);
++ rc = tpm2_submit_command (tag, TPM_CC_LoadExternal, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_Unseal (const TPMI_DH_OBJECT itemHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ TPM2B_SENSITIVE_DATA *outData,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_unseal (const TPMI_DH_OBJECT_t itemHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ TPM2B_SENSITIVE_DATA_t *outData,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPM2B_SENSITIVE_DATA outDataTmp;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPM2B_SENSITIVE_DATA_t outDataTmp;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (outData == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_Unseal, &responseCode, &in, &out);
++ rc = tpm2_submit_command (tag, TPM_CC_Unseal, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_FlushContext (const TPMI_DH_CONTEXT handle)
++TPM_RC_t
++grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPM_RC responseCode;
++ TPM_RC_t responseCode;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (TPM_ST_NO_SESSIONS, TPM_CC_FlushContext,
-+ &responseCode, &in, &out);
++ rc = tpm2_submit_command (TPM_ST_NO_SESSIONS, TPM_CC_FlushContext, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_PCR_Read (const TPMS_AUTH_COMMAND *authCommand,
-+ const TPML_PCR_SELECTION *pcrSelectionIn,
-+ grub_uint32_t *pcrUpdateCounter,
-+ TPML_PCR_SELECTION *pcrSelectionOut,
-+ TPML_DIGEST *pcrValues,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPML_PCR_SELECTION_t *pcrSelectionIn,
++ grub_uint32_t *pcrUpdateCounter,
++ TPML_PCR_SELECTION_t *pcrSelectionOut,
++ TPML_DIGEST_t *pcrValues,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ grub_uint32_t pcrUpdateCounterTmp;
-+ TPML_PCR_SELECTION pcrSelectionOutTmp;
-+ TPML_DIGEST pcrValuesTmp;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPML_PCR_SELECTION_t pcrSelectionOutTmp;
++ TPML_DIGEST_t pcrValuesTmp;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ if (pcrSelectionIn == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_PCR_Read, &responseCode, &in,
-+ &out);
++ rc = tpm2_submit_command (tag, TPM_CC_PCR_Read, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_PolicyGetDigest (const TPMI_SH_POLICY policySession,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ TPM2B_DIGEST *policyDigest,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_policygetdigest (const TPMI_SH_POLICY_t policySession,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ TPM2B_DIGEST_t *policyDigest,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPM2B_DIGEST policyDigestTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPM2B_DIGEST_t policyDigestTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ if (authResponse == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyGetDigest, &responseCode,
-+ &in, &out);
++ rc = tpm2_submit_command (tag, TPM_CC_PolicyGetDigest, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_Create (const TPMI_DH_OBJECT parentHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_SENSITIVE_CREATE *inSensitive,
-+ const TPM2B_PUBLIC *inPublic,
-+ const TPM2B_DATA *outsideInfo,
-+ const TPML_PCR_SELECTION *creationPCR,
-+ TPM2B_PRIVATE *outPrivate,
-+ TPM2B_PUBLIC *outPublic,
-+ TPM2B_CREATION_DATA *creationData,
-+ TPM2B_DIGEST *creationHash,
-+ TPMT_TK_CREATION *creationTicket,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_create (const TPMI_DH_OBJECT_t parentHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
++ const TPM2B_PUBLIC_t *inPublic,
++ const TPM2B_DATA_t *outsideInfo,
++ const TPML_PCR_SELECTION_t *creationPCR,
++ TPM2B_PRIVATE_t *outPrivate,
++ TPM2B_PUBLIC_t *outPublic,
++ TPM2B_CREATION_DATA_t *creationData,
++ TPM2B_DIGEST_t *creationHash,
++ TPMT_TK_CREATION_t *creationTicket,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPM2B_PUBLIC outPublicTmp;
-+ TPM2B_PRIVATE outPrivateTmp;
-+ TPM2B_CREATION_DATA creationDataTmp;
-+ TPM2B_DIGEST creationHashTmp;
-+ TPMT_TK_CREATION creationTicketTmp;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS:TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
-+ TPM_RC rc;
++ TPM2B_PUBLIC_t outPublicTmp;
++ TPM2B_PRIVATE_t outPrivateTmp;
++ TPM2B_CREATION_DATA_t creationDataTmp;
++ TPM2B_DIGEST_t creationHashTmp;
++ TPMT_TK_CREATION_t creationTicketTmp;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS:TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
++ TPM_RC_t rc;
+ grub_uint32_t parameterSize;
+
+ if (inSensitive == NULL || inPublic == NULL || outsideInfo == NULL ||
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_Create, &responseCode, &in,
-+ &out);
++ rc = tpm2_submit_command (tag, TPM_CC_Create, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_EvictControl (const TPMI_RH_PROVISION auth,
-+ const TPMI_DH_OBJECT objectHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPMI_DH_PERSISTENT persistentHandle,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_evictcontrol (const TPMI_RH_PROVISION_t auth,
++ const TPMI_DH_OBJECT_t objectHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPMI_DH_PERSISTENT_t persistentHandle,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
-+ TPM_RC rc;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
++ TPM_RC_t rc;
+ grub_uint32_t parameterSize;
+
+ if (authResponse == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_EvictControl, &responseCode, &in,
-+ &out);
++ rc = tpm2_submit_command (tag, TPM_CC_EvictControl, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_Hash (const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_MAX_BUFFER *data,
-+ const TPMI_ALG_HASH hashAlg,
-+ const TPMI_RH_HIERARCHY hierarchy,
-+ TPM2B_DIGEST *outHash,
-+ TPMT_TK_HASHCHECK *validation,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_hash (const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_MAX_BUFFER_t *data,
++ const TPMI_ALG_HASH_t hashAlg,
++ const TPMI_RH_HIERARCHY_t hierarchy,
++ TPM2B_DIGEST_t *outHash,
++ TPMT_TK_HASHCHECK_t *validation,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPM2B_DIGEST outHashTmp;
-+ TPMT_TK_HASHCHECK validationTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPM2B_DIGEST_t outHashTmp;
++ TPMT_TK_HASHCHECK_t validationTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (hashAlg == TPM_ALG_NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_Hash, &responseCode, &in, &out);
++ rc = tpm2_submit_command (tag, TPM_CC_Hash, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_VerifySignature (const TPMI_DH_OBJECT keyHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_DIGEST *digest,
-+ const TPMT_SIGNATURE *signature,
-+ TPMT_TK_VERIFIED *validation,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_verifysignature (const TPMI_DH_OBJECT_t keyHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_DIGEST_t *digest,
++ const TPMT_SIGNATURE_t *signature,
++ TPMT_TK_VERIFIED_t *validation,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPMT_TK_VERIFIED validationTmp;
-+ TPM_RC responseCode;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPMT_TK_VERIFIED_t validationTmp;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (digest == NULL || signature == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_VerifySignature, &responseCode, &in, &out);
++ rc = tpm2_submit_command (tag, TPM_CC_VerifySignature, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_PolicyAuthorize (const TPMI_SH_POLICY policySession,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_DIGEST *approvedPolicy,
-+ const TPM2B_NONCE *policyRef,
-+ const TPM2B_NAME *keySign,
-+ const TPMT_TK_VERIFIED *checkTicket,
-+ TPMS_AUTH_RESPONSE *authResponse)
++TPM_RC_t
++grub_tpm2_policyauthorize (const TPMI_SH_POLICY_t policySession,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_DIGEST_t *approvedPolicy,
++ const TPM2B_NONCE_t *policyRef,
++ const TPM2B_NAME_t *keySign,
++ const TPMT_TK_VERIFIED_t *checkTicket,
++ TPMS_AUTH_RESPONSE_t *authResponse)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMS_AUTH_RESPONSE authResponseTmp;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPMS_AUTH_RESPONSE_t authResponseTmp;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (approvedPolicy == NULL || keySign == NULL || checkTicket == NULL)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_PolicyAuthorize, &responseCode, &in, &out);
++ rc = tpm2_submit_command (tag, TPM_CC_PolicyAuthorize, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+ return TPM_RC_SUCCESS;
+}
+
-+TPM_RC
-+TPM2_TestParms (const TPMT_PUBLIC_PARMS *parms,
-+ const TPMS_AUTH_COMMAND* authCommand)
++TPM_RC_t
++grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
++ const TPMS_AUTH_COMMAND_t *authCommand)
+{
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
-+ TPMI_ST_COMMAND_TAG tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
-+ TPM_RC responseCode;
++ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
++ TPM_RC_t responseCode;
+
+ if (parms == NULL)
+ return TPM_RC_VALUE;
@@ grub-core/lib/tss2/tpm2_cmd.c (new)
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
-+ rc = grub_tpm2_submit_command (tag, TPM_CC_TestParms, &responseCode, &in,
++ rc = tpm2_submit_command (tag, TPM_CC_TestParms, &responseCode, &in,
+ &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
@@ grub-core/lib/tss2/tpm2_cmd.h (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/lib/tss2/tpm2_cmd.h (new)
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
-+#ifndef GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER
-+#define GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER 1
++#ifndef GRUB_TPM2_COMMANDS_HEADER
++#define GRUB_TPM2_COMMANDS_HEADER 1
+
+#include <tss2_structs.h>
+
-+TPM_RC
-+TPM2_CreatePrimary (const TPMI_RH_HIERARCHY primaryHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_SENSITIVE_CREATE *inSensitive,
-+ const TPM2B_PUBLIC *inPublic,
-+ const TPM2B_DATA *outsideInfo,
-+ const TPML_PCR_SELECTION *creationPCR,
-+ TPM_HANDLE *objectHandle,
-+ TPM2B_PUBLIC *outPublic,
-+ TPM2B_CREATION_DATA *creationData,
-+ TPM2B_DIGEST *creationHash,
-+ TPMT_TK_CREATION *creationTicket,
-+ TPM2B_NAME *name,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_StartAuthSession (const TPMI_DH_OBJECT tpmKey,
-+ const TPMI_DH_ENTITY bind,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_NONCE *nonceCaller,
-+ const TPM2B_ENCRYPTED_SECRET *encryptedSalt,
-+ const TPM_SE sessionType,
-+ const TPMT_SYM_DEF *symmetric,
-+ const TPMI_ALG_HASH authHash,
-+ TPMI_SH_AUTH_SESSION *sessionHandle,
-+ TPM2B_NONCE *nonceTpm,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_PolicyPCR (const TPMI_SH_POLICY policySession,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_DIGEST *pcrDigest,
-+ const TPML_PCR_SELECTION *pcrs,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_ReadPublic (const TPMI_DH_OBJECT objectHandle,
-+ const TPMS_AUTH_COMMAND* authCommand,
-+ TPM2B_PUBLIC *outPublic);
-+
-+TPM_RC
-+TPM2_Load (const TPMI_DH_OBJECT parent_handle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_PRIVATE *inPrivate,
-+ const TPM2B_PUBLIC *inPublic,
-+ TPM_HANDLE *objectHandle,
-+ TPM2B_NAME *name,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_LoadExternal (const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_SENSITIVE *inPrivate,
-+ const TPM2B_PUBLIC *inPublic,
-+ const TPMI_RH_HIERARCHY hierarchy,
-+ TPM_HANDLE *objectHandle,
-+ TPM2B_NAME *name,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_Unseal (const TPMI_DH_OBJECT item_handle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ TPM2B_SENSITIVE_DATA *outData,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_FlushContext (const TPMI_DH_CONTEXT handle);
-+
-+TPM_RC
-+TPM2_PCR_Read (const TPMS_AUTH_COMMAND *authCommand,
-+ const TPML_PCR_SELECTION *pcrSelectionIn,
-+ grub_uint32_t *pcrUpdateCounter,
-+ TPML_PCR_SELECTION *pcrSelectionOut,
-+ TPML_DIGEST *pcrValues,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_PolicyGetDigest (const TPMI_SH_POLICY policySession,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ TPM2B_DIGEST *policyDigest,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_Create (const TPMI_DH_OBJECT parentHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_SENSITIVE_CREATE *inSensitive,
-+ const TPM2B_PUBLIC *inPublic,
-+ const TPM2B_DATA *outsideInfo,
-+ const TPML_PCR_SELECTION *creationPCR,
-+ TPM2B_PRIVATE *outPrivate,
-+ TPM2B_PUBLIC *outPublic,
-+ TPM2B_CREATION_DATA *creationData,
-+ TPM2B_DIGEST *creationHash,
-+ TPMT_TK_CREATION *creationTicket,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_EvictControl (const TPMI_RH_PROVISION auth,
-+ const TPMI_DH_OBJECT objectHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPMI_DH_PERSISTENT persistentHandle,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_Hash (const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_MAX_BUFFER *data,
-+ const TPMI_ALG_HASH hashAlg,
-+ const TPMI_RH_HIERARCHY hierarchy,
-+ TPM2B_DIGEST *outHash,
-+ TPMT_TK_HASHCHECK *validation,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_VerifySignature (const TPMI_DH_OBJECT keyHandle,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_DIGEST *digest,
-+ const TPMT_SIGNATURE *signature,
-+ TPMT_TK_VERIFIED *validation,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_PolicyAuthorize (const TPMI_SH_POLICY policySession,
-+ const TPMS_AUTH_COMMAND *authCommand,
-+ const TPM2B_DIGEST *approvedPolicy,
-+ const TPM2B_NONCE *policyRef,
-+ const TPM2B_NAME *keySign,
-+ const TPMT_TK_VERIFIED *checkTicket,
-+ TPMS_AUTH_RESPONSE *authResponse);
-+
-+TPM_RC
-+TPM2_TestParms (const TPMT_PUBLIC_PARMS *parms,
-+ const TPMS_AUTH_COMMAND* authCommand);
-+
-+#endif /* ! GRUB_TPM2_INTERNAL_FUNCTIONS_HEADER */
++extern TPM_RC_t
++grub_tpm2_createprimary (const TPMI_RH_HIERARCHY_t primaryHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
++ const TPM2B_PUBLIC_t *inPublic,
++ const TPM2B_DATA_t *outsideInfo,
++ const TPML_PCR_SELECTION_t *creationPCR,
++ TPM_HANDLE_t *objectHandle,
++ TPM2B_PUBLIC_t *outPublic,
++ TPM2B_CREATION_DATA_t *creationData,
++ TPM2B_DIGEST_t *creationHash,
++ TPMT_TK_CREATION_t *creationTicket,
++ TPM2B_NAME_t *name,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_startauthsession (const TPMI_DH_OBJECT_t tpmKey,
++ const TPMI_DH_ENTITY_t bind,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_NONCE_t *nonceCaller,
++ const TPM2B_ENCRYPTED_SECRET_t *encryptedSalt,
++ const TPM_SE_t sessionType,
++ const TPMT_SYM_DEF_t *symmetric,
++ const TPMI_ALG_HASH_t authHash,
++ TPMI_SH_AUTH_SESSION_t *sessionHandle,
++ TPM2B_NONCE_t *nonceTpm,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_policypcr (const TPMI_SH_POLICY_t policySession,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_DIGEST_t *pcrDigest,
++ const TPML_PCR_SELECTION_t *pcrs,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_readpublic (const TPMI_DH_OBJECT_t objectHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ TPM2B_PUBLIC_t *outPublic);
++
++extern TPM_RC_t
++grub_tpm2_load (const TPMI_DH_OBJECT_t parent_handle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_PRIVATE_t *inPrivate,
++ const TPM2B_PUBLIC_t *inPublic,
++ TPM_HANDLE_t *objectHandle,
++ TPM2B_NAME_t *name,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_loadexternal (const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_SENSITIVE_t *inPrivate,
++ const TPM2B_PUBLIC_t *inPublic,
++ const TPMI_RH_HIERARCHY_t hierarchy,
++ TPM_HANDLE_t *objectHandle,
++ TPM2B_NAME_t *name,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_unseal (const TPMI_DH_OBJECT_t item_handle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ TPM2B_SENSITIVE_DATA_t *outData,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle);
++
++extern TPM_RC_t
++grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPML_PCR_SELECTION_t *pcrSelectionIn,
++ grub_uint32_t *pcrUpdateCounter,
++ TPML_PCR_SELECTION_t *pcrSelectionOut,
++ TPML_DIGEST_t *pcrValues,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_policygetdigest (const TPMI_SH_POLICY_t policySession,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ TPM2B_DIGEST_t *policyDigest,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_create (const TPMI_DH_OBJECT_t parentHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
++ const TPM2B_PUBLIC_t *inPublic,
++ const TPM2B_DATA_t *outsideInfo,
++ const TPML_PCR_SELECTION_t *creationPCR,
++ TPM2B_PRIVATE_t *outPrivate,
++ TPM2B_PUBLIC_t *outPublic,
++ TPM2B_CREATION_DATA_t *creationData,
++ TPM2B_DIGEST_t *creationHash,
++ TPMT_TK_CREATION_t *creationTicket,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_evictcontrol (const TPMI_RH_PROVISION_t auth,
++ const TPMI_DH_OBJECT_t objectHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPMI_DH_PERSISTENT_t persistentHandle,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_hash (const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_MAX_BUFFER_t *data,
++ const TPMI_ALG_HASH_t hashAlg,
++ const TPMI_RH_HIERARCHY_t hierarchy,
++ TPM2B_DIGEST_t *outHash,
++ TPMT_TK_HASHCHECK_t *validation,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_verifysignature (const TPMI_DH_OBJECT_t keyHandle,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_DIGEST_t *digest,
++ const TPMT_SIGNATURE_t *signature,
++ TPMT_TK_VERIFIED_t *validation,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_policyauthorize (const TPMI_SH_POLICY_t policySession,
++ const TPMS_AUTH_COMMAND_t *authCommand,
++ const TPM2B_DIGEST_t *approvedPolicy,
++ const TPM2B_NONCE_t *policyRef,
++ const TPM2B_NAME_t *keySign,
++ const TPMT_TK_VERIFIED_t *checkTicket,
++ TPMS_AUTH_RESPONSE_t *authResponse);
++
++extern TPM_RC_t
++grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
++ const TPMS_AUTH_COMMAND_t *authCommand);
++
++#endif /* ! GRUB_TPM2_COMMANDS_HEADER */
## grub-core/lib/tss2/tss2.c (new) ##
@@
16: dd1efc0fe ! 22: 12d09a2c8 key_protector: Add TPM2 Key Protector
@@ grub-core/commands/tpm2_key_protector/args.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/commands/tpm2_key_protector/args.c (new)
+ {
+ next_pcr = grub_strchr (current_pcr, ',');
+ if (next_pcr == current_pcr)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Empty entry in PCR list"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Empty entry in PCR list");
+ if (next_pcr != NULL)
+ *next_pcr = '\0';
+
+ grub_errno = GRUB_ERR_NONE;
+ pcr = grub_strtoul (current_pcr, &pcr_end, 10);
+ if (*current_pcr == '\0' || *pcr_end != '\0')
-+ return grub_error (GRUB_ERR_BAD_NUMBER, N_("Entry '%s' in PCR list is not a number"), current_pcr);
++ return grub_error (GRUB_ERR_BAD_NUMBER, "Entry '%s' in PCR list is not a number", current_pcr);
+
+ if (pcr > TPM_MAX_PCRS)
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Entry %lu in PCR list is too large to be a PCR number, PCR numbers range from 0 to %u"), pcr, TPM_MAX_PCRS);
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Entry %" PRIuGRUB_UINT64_T " in PCR list is too large to be a PCR number, PCR numbers range from 0 to %u", pcr, TPM_MAX_PCRS);
+
+ pcrs[i] = (grub_uint8_t) pcr;
+ ++(*pcr_count);
@@ grub-core/commands/tpm2_key_protector/args.c (new)
+
+ current_pcr = next_pcr + 1;
+ if (*current_pcr == '\0')
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Trailing comma at the end of PCR list"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Trailing comma at the end of PCR list");
+ }
+
+ if (i == TPM_MAX_PCRS)
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Too many PCRs in PCR list, the maximum number of PCRs is %u"), TPM_MAX_PCRS);
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Too many PCRs in PCR list, the maximum number of PCRs is %u", TPM_MAX_PCRS);
+
+ return GRUB_ERR_NONE;
+}
@@ grub-core/commands/tpm2_key_protector/args.c (new)
+ srk_type->detail.rsa_bits = 2048;
+ }
+ else
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Value '%s' is not a valid asymmetric key type"), value);
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid asymmetric key type", value);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
-+grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank)
++grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID_t *bank)
+{
+ if (grub_strcasecmp (value, "SHA1") == 0)
+ *bank = TPM_ALG_SHA1;
@@ grub-core/commands/tpm2_key_protector/args.c (new)
+ else if (grub_strcasecmp (value, "SHA512") == 0)
+ *bank = TPM_ALG_SHA512;
+ else
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
-+ N_("Value '%s' is not a valid PCR bank"), value);
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid PCR bank", value);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
-+grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle)
++grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle)
+{
+ grub_uint64_t num;
+ const char *str_end;
@@ grub-core/commands/tpm2_key_protector/args.c (new)
+ grub_errno = GRUB_ERR_NONE;
+ num = grub_strtoul (value, &str_end, 0);
+ if (*value == '\0' || *str_end != '\0')
-+ return grub_error (GRUB_ERR_BAD_NUMBER, N_("TPM handle value '%s' is not a number"), value);
++ return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is not a number", value);
+
+ if (num > GRUB_UINT_MAX)
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers"), num);
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
+
-+ *handle = (TPM_HANDLE) num;
++ *handle = (TPM_HANDLE_t) num;
+
+ return GRUB_ERR_NONE;
+}
@@ grub-core/commands/tpm2_key_protector/module.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ grub_uint8_t pcrs[TPM_MAX_PCRS];
+ grub_uint8_t pcr_count;
+ grub_srk_type_t srk_type;
-+ TPM_ALG_ID bank;
++ TPM_ALG_ID_t bank;
+ const char *tpm2key;
+ const char *keyfile;
-+ TPM_HANDLE srk;
-+ TPM_HANDLE nv;
++ TPM_HANDLE_t srk;
++ TPM_HANDLE_t nv;
+};
+
+static const struct grub_arg_option grub_tpm2_protector_init_cmd_options[] =
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+static struct grub_tpm2_protector_context grub_tpm2_protector_ctx = {0};
+
+static grub_err_t
-+grub_tpm2_protector_srk_read_file (const char *filepath, void **buffer,
-+ grub_size_t *buffer_size)
++tpm2_protector_srk_read_file (const char *filepath, void **buffer, grub_size_t *buffer_size)
+{
+ grub_file_t file;
+ grub_off_t file_size;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ grub_off_t read_n;
+ grub_err_t err;
+
-+ /* Using GRUB_FILE_TYPE_SIGNATURE ensures we do not hash the keyfile into PCR9
-+ * otherwise we'll never be able to predict the value of PCR9 at unseal time */
++ /*
++ * Using GRUB_FILE_TYPE_SIGNATURE ensures we do not hash the keyfile into PCR9
++ * otherwise we'll never be able to predict the value of PCR9 at unseal time
++ */
+ file = grub_file_open (filepath, GRUB_FILE_TYPE_SIGNATURE);
+ if (file == NULL)
+ {
+ /* Push errno from grub_file_open() into the error message stack */
+ grub_error_push();
-+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("Could not open file: %s\n"), filepath);
++ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "Could not open file: %s", filepath);
+ goto error;
+ }
+
+ file_size = grub_file_size (file);
+ if (file_size == 0)
+ {
-+ err = grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Could not read file size: %s"), filepath);
++ err = grub_error (GRUB_ERR_OUT_OF_RANGE, "Could not read file size: %s", filepath);
+ goto error;
+ }
+
+ read_buffer = grub_malloc (file_size);
+ if (read_buffer == NULL)
+ {
-+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Could not allocate buffer for %s"), filepath);
++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate buffer for %s", filepath);
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ if (read_n != file_size)
+ {
+ grub_free (read_buffer);
-+ err = grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Could not retrieve file contents: %s"), filepath);
++ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "Could not retrieve file contents: %s", filepath);
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_srk_unmarshal_keyfile (void *sealed_key,
-+ grub_size_t sealed_key_size,
-+ tpm2_sealed_key_t *sk)
++tpm2_protector_srk_unmarshal_keyfile (void *sealed_key,
++ grub_size_t sealed_key_size,
++ tpm2_sealed_key_t *sk)
+{
+ struct grub_tpm2_buffer buf;
+
+ grub_tpm2_buffer_init (&buf);
+ if (sealed_key_size > buf.cap)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Sealed key larger than %" PRIuGRUB_SIZE " bytes"), buf.cap);
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Sealed key larger than %" PRIuGRUB_SIZE " bytes", buf.cap);
+
+ grub_memcpy (buf.data, sealed_key, sealed_key_size);
+ buf.size = sealed_key_size;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ grub_Tss2_MU_TPM2B_PRIVATE_Unmarshal (&buf, &sk->private);
+
+ if (buf.error != 0)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Malformed TPM wire key file"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Malformed TPM wire key file");
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
-+grub_tpm2_protector_srk_unmarshal_tpm2key (void *sealed_key,
-+ grub_size_t sealed_key_size,
-+ tpm2key_policy_t *policy_seq,
-+ tpm2key_authpolicy_t *authpol_seq,
-+ grub_uint8_t *rsaparent,
-+ grub_uint32_t *parent,
-+ tpm2_sealed_key_t *sk)
++tpm2_protector_srk_unmarshal_tpm2key (void *sealed_key,
++ grub_size_t sealed_key_size,
++ tpm2key_policy_t *policy_seq,
++ tpm2key_authpolicy_t *authpol_seq,
++ grub_uint8_t *rsaparent,
++ grub_uint32_t *parent,
++ tpm2_sealed_key_t *sk)
+{
+ asn1_node tpm2key = NULL;
+ grub_uint8_t rsaparent_tmp;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ grub_tpm2_buffer_init (&buf);
+ if (sealed_pub_size + sealed_priv_size > buf.cap)
+ {
-+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Sealed key larger than %" PRIuGRUB_SIZE " bytes"), buf.cap);
++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "Sealed key larger than %" PRIuGRUB_SIZE " bytes", buf.cap);
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+
+ if (buf.error != 0)
+ {
-+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Malformed TPM 2.0 key file"));
++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "Malformed TPM 2.0 key file");
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+
+/* Check if the SRK exists in the specified handle */
+static grub_err_t
-+grub_tpm2_protector_srk_check (const TPM_HANDLE srk_handle)
++tpm2_protector_srk_check (const TPM_HANDLE_t srk_handle)
+{
-+ TPM_RC rc;
-+ TPM2B_PUBLIC public;
++ TPM_RC_t rc;
++ TPM2B_PUBLIC_t public;
+
+ /* Find SRK */
-+ rc = TPM2_ReadPublic (srk_handle, NULL, &public);
++ rc = grub_tpm2_readpublic (srk_handle, NULL, &public);
+ if (rc == TPM_RC_SUCCESS)
+ return GRUB_ERR_NONE;
+
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x)"), srk_handle, rc);
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x)", srk_handle, rc);
+}
+
+/* Get the SRK with the template */
+static grub_err_t
-+grub_tpm2_protector_srk_get (const grub_srk_type_t srk_type,
-+ const TPM_HANDLE parent,
-+ TPM_HANDLE *srk_handle)
++tpm2_protector_srk_get (const grub_srk_type_t srk_type,
++ const TPM_HANDLE_t parent,
++ TPM_HANDLE_t *srk_handle)
+{
-+ TPM_RC rc;
-+ TPMT_PUBLIC_PARMS parms = {0};
-+ TPMS_AUTH_COMMAND authCommand = {0};
-+ TPM2B_SENSITIVE_CREATE inSensitive = {0};
-+ TPM2B_PUBLIC inPublic = {0};
-+ TPM2B_DATA outsideInfo = {0};
-+ TPML_PCR_SELECTION creationPcr = {0};
-+ TPM2B_PUBLIC outPublic = {0};
-+ TPM2B_CREATION_DATA creationData = {0};
-+ TPM2B_DIGEST creationHash = {0};
-+ TPMT_TK_CREATION creationTicket = {0};
-+ TPM2B_NAME srkName = {0};
-+ TPM_HANDLE tmp_handle = 0;
++ TPM_RC_t rc;
++ TPMT_PUBLIC_PARMS_t parms = {0};
++ TPMS_AUTH_COMMAND_t authCommand = {0};
++ TPM2B_SENSITIVE_CREATE_t inSensitive = {0};
++ TPM2B_PUBLIC_t inPublic = {0};
++ TPM2B_DATA_t outsideInfo = {0};
++ TPML_PCR_SELECTION_t creationPcr = {0};
++ TPM2B_PUBLIC_t outPublic = {0};
++ TPM2B_CREATION_DATA_t creationData = {0};
++ TPM2B_DIGEST_t creationHash = {0};
++ TPMT_TK_CREATION_t creationTicket = {0};
++ TPM2B_NAME_t srkName = {0};
++ TPM_HANDLE_t tmp_handle = 0;
+
+ inPublic.publicArea.type = srk_type.type;
+ inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+ }
+ else
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown SRK algorithm"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown SRK algorithm");
+
+ /* Test the parameters before SRK generation */
+ parms.type = srk_type.type;
+ grub_memcpy (&parms.parameters, &inPublic.publicArea.parameters,
-+ sizeof (TPMU_PUBLIC_PARMS));
++ sizeof (TPMU_PUBLIC_PARMS_t));
+
-+ rc = TPM2_TestParms (&parms, NULL);
++ rc = grub_tpm2_testparms (&parms, NULL);
+ if (rc != TPM_RC_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unsupported SRK template (TPM2_TestParms: 0x%x)"), rc);
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported SRK template (TPM2_TestParms: 0x%x)", rc);
+
+ /* Create SRK */
+ authCommand.sessionHandle = TPM_RS_PW;
-+ rc = TPM2_CreatePrimary (parent, &authCommand, &inSensitive, &inPublic,
-+ &outsideInfo, &creationPcr, &tmp_handle, &outPublic,
-+ &creationData, &creationHash, &creationTicket,
-+ &srkName, NULL);
++ rc = grub_tpm2_createprimary (parent, &authCommand, &inSensitive, &inPublic,
++ &outsideInfo, &creationPcr, &tmp_handle, &outPublic,
++ &creationData, &creationHash, &creationTicket,
++ &srkName, NULL);
+ if (rc != TPM_RC_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("Could not create SRK (TPM2_CreatePrimary: 0x%x)"), rc);
++ return grub_error (GRUB_ERR_BAD_DEVICE, "Could not create SRK (TPM2_CreatePrimary: 0x%x)", rc);
+
+ *srk_handle = tmp_handle;
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ * - Other: Something went wrong.
+ */
+static grub_err_t
-+grub_tpm2_protector_srk_load (const grub_srk_type_t srk_type,
-+ const tpm2_sealed_key_t *sealed_key,
-+ const TPM_HANDLE parent,
-+ TPM_HANDLE *sealed_handle,
-+ TPM_HANDLE *srk_handle)
++tpm2_protector_srk_load (const grub_srk_type_t srk_type,
++ const tpm2_sealed_key_t *sealed_key,
++ const TPM_HANDLE_t parent,
++ TPM_HANDLE_t *sealed_handle,
++ TPM_HANDLE_t *srk_handle)
+{
-+ TPMS_AUTH_COMMAND authCmd = {0};
-+ TPM2B_NAME name = {0};
-+ TPM_RC rc;
++ TPMS_AUTH_COMMAND_t authCmd = {0};
++ TPM2B_NAME_t name = {0};
++ TPM_RC_t rc;
+ grub_err_t err;
+
+ if (srk_handle == NULL)
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+
+ if (*srk_handle != 0)
+ {
-+ err = grub_tpm2_protector_srk_check (*srk_handle);
++ err = tpm2_protector_srk_check (*srk_handle);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ else
+ {
-+ err = grub_tpm2_protector_srk_get (srk_type, parent, srk_handle);
++ err = tpm2_protector_srk_get (srk_type, parent, srk_handle);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ /* Load the sealed key and associate it with the SRK */
+ authCmd.sessionHandle = TPM_RS_PW;
-+ rc = TPM2_Load (*srk_handle, &authCmd, &sealed_key->private, &sealed_key->public,
-+ sealed_handle, &name, NULL);
++ rc = grub_tpm2_load (*srk_handle, &authCmd, &sealed_key->private, &sealed_key->public,
++ sealed_handle, &name, NULL);
+ /*
+ * If TPM2_Load returns (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1), then it
+ * implies the wrong SRK is used.
+ */
+ if (rc == (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1))
+ {
-+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("SRK not matched"));
++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "SRK not matched");
+ goto error;
+ }
+ else if (rc != TPM_RC_SUCCESS)
+ {
-+ err = grub_error (GRUB_ERR_BAD_DEVICE, N_("Failed to load sealed key (TPM2_Load: 0x%x)"), rc);
++ err = grub_error (GRUB_ERR_BAD_DEVICE, "Failed to load sealed key (TPM2_Load: 0x%x)", rc);
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+
+ error:
+ if (!TPM_HT_IS_PERSISTENT (*srk_handle))
-+ TPM2_FlushContext (*srk_handle);
++ grub_tpm2_flushcontext (*srk_handle);
+
+ return err;
+}
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_load_key (const struct grub_tpm2_protector_context *ctx,
-+ const tpm2_sealed_key_t *sealed_key,
-+ const TPM_HANDLE parent_handle,
-+ TPM_HANDLE *sealed_handle,
-+ TPM_HANDLE *srk_handle)
++tpm2_protector_load_key (const struct grub_tpm2_protector_context *ctx,
++ const tpm2_sealed_key_t *sealed_key,
++ const TPM_HANDLE_t parent_handle,
++ TPM_HANDLE_t *sealed_handle,
++ TPM_HANDLE_t *srk_handle)
+{
+ grub_err_t err;
+ int i;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ /* Try the given persistent SRK if exists */
+ if (*srk_handle != 0)
+ {
-+ err = grub_tpm2_protector_srk_load (ctx->srk_type, sealed_key,
-+ parent_handle, sealed_handle,
-+ srk_handle);
++ err = tpm2_protector_srk_load (ctx->srk_type, sealed_key,
++ parent_handle, sealed_handle,
++ srk_handle);
+ if (err != GRUB_ERR_BAD_ARGUMENT)
+ return err;
+
+ grub_print_error ();
-+ grub_printf_ (N_("Trying the specified SRK algorithm: %s\n"), srk_type_to_name (ctx->srk_type));
++ grub_printf ("Trying the specified SRK algorithm: %s\n", srk_type_to_name (ctx->srk_type));
+ grub_errno = GRUB_ERR_NONE;
+ *srk_handle = 0;
+ }
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ /* Try the specified algorithm for the SRK template */
+ if (*srk_handle == 0)
+ {
-+ err = grub_tpm2_protector_srk_load (ctx->srk_type, sealed_key,
-+ parent_handle, sealed_handle,
-+ srk_handle);
++ err = tpm2_protector_srk_load (ctx->srk_type, sealed_key,
++ parent_handle, sealed_handle,
++ srk_handle);
+ if (err != GRUB_ERR_BAD_ARGUMENT)
+ return err;
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ fallback_srks[i].detail.ecc_curve == ctx->srk_type.detail.ecc_curve))
+ continue;
+
-+ grub_printf_ (N_("Trying fallback %s template\n"), srk_type_to_name (fallback_srks[i]));
++ grub_printf ("Trying fallback %s template\n", srk_type_to_name (fallback_srks[i]));
+
+ *srk_handle = 0;
+
-+ err = grub_tpm2_protector_srk_load (fallback_srks[i], sealed_key,
-+ parent_handle, sealed_handle,
-+ srk_handle);
++ err = tpm2_protector_srk_load (fallback_srks[i], sealed_key,
++ parent_handle, sealed_handle,
++ srk_handle);
+ if (err != GRUB_ERR_BAD_ARGUMENT)
+ return err;
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION session,
-+ struct grub_tpm2_buffer *cmd_buf)
++tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION_t session, struct grub_tpm2_buffer *cmd_buf)
+{
-+ TPM2B_DIGEST pcr_digest;
-+ TPML_PCR_SELECTION pcr_sel;
-+ TPM_RC rc;
++ TPM2B_DIGEST_t pcr_digest;
++ TPML_PCR_SELECTION_t pcr_sel;
++ TPM_RC_t rc;
+
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (cmd_buf, &pcr_digest);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Unmarshal (cmd_buf, &pcr_sel);
+ if (cmd_buf->error != 0)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Failed to unmarshal CommandPolicy for TPM2_PolicyPCR"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to unmarshal CommandPolicy for TPM2_PolicyPCR");
+
-+ rc = TPM2_PolicyPCR (session, NULL, &pcr_digest, &pcr_sel, NULL);
++ rc = grub_tpm2_policypcr (session, NULL, &pcr_digest, &pcr_sel, NULL);
+ if (rc != TPM_RC_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x)"), rc);
++ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x)", rc);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
-+grub_tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION session)
++tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION_t session)
+{
+ struct grub_tpm2_buffer buf;
+ grub_err_t err;
+
+ grub_tpm2_buffer_init (&buf);
+ if (policy->cmd_policy_len > buf.cap)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("CommandPolicy larger than TPM buffer"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "CommandPolicy larger than TPM buffer");
+
+ grub_memcpy (buf.data, policy->cmd_policy, policy->cmd_policy_len);
+ buf.size = policy->cmd_policy_len;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ switch (policy->cmd_code)
+ {
+ case TPM_CC_PolicyPCR:
-+ err = grub_tpm2_protector_policypcr (session, &buf);
++ err = tpm2_protector_policypcr (session, &buf);
+ break;
+ default:
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown TPM Command: 0x%x"), policy->cmd_code);
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown TPM Command: 0x%x", policy->cmd_code);
+ }
+
+ return err;
+}
+
+static grub_err_t
-+grub_tpm2_protector_enforce_policy_seq (tpm2key_policy_t policy_seq,
-+ TPMI_SH_AUTH_SESSION session)
++tpm2_protector_enforce_policy_seq (tpm2key_policy_t policy_seq, TPMI_SH_AUTH_SESSION_t session)
+{
+ tpm2key_policy_t policy;
+ grub_err_t err;
+
+ FOR_LIST_ELEMENTS (policy, policy_seq)
+ {
-+ err = grub_tpm2_protector_enforce_policy (policy, session);
++ err = tpm2_protector_enforce_policy (policy, session);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_simple_policy_seq (const struct grub_tpm2_protector_context *ctx,
-+ tpm2key_policy_t *policy_seq)
++tpm2_protector_simple_policy_seq (const struct grub_tpm2_protector_context *ctx,
++ tpm2key_policy_t *policy_seq)
+{
+ tpm2key_policy_t policy = NULL;
+ struct grub_tpm2_buffer buf;
-+ TPML_PCR_SELECTION pcr_sel = {
++ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE sealed_handle,
-+ grub_uint8_t **key, grub_size_t *key_size)
++tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE_t sealed_handle,
++ grub_uint8_t **key, grub_size_t *key_size)
+{
-+ TPMS_AUTH_COMMAND authCmd = {0};
-+ TPM2B_SENSITIVE_DATA data;
-+ TPM2B_NONCE nonceCaller = {0};
-+ TPMT_SYM_DEF symmetric = {0};
-+ TPMI_SH_AUTH_SESSION session;
++ TPMS_AUTH_COMMAND_t authCmd = {0};
++ TPM2B_SENSITIVE_DATA_t data;
++ TPM2B_NONCE_t nonceCaller = {0};
++ TPMT_SYM_DEF_t symmetric = {0};
++ TPMI_SH_AUTH_SESSION_t session;
+ grub_uint8_t *key_out;
-+ TPM_RC rc;
++ TPM_RC_t rc;
+ grub_err_t err;
+
+ /* Start Auth Session */
+ nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
+ symmetric.algorithm = TPM_ALG_NULL;
-+ rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, NULL, &nonceCaller, NULL,
-+ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256,
-+ &session, NULL, NULL);
++ rc = grub_tpm2_startauthsession (TPM_RH_NULL, TPM_RH_NULL, NULL, &nonceCaller, NULL,
++ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256,
++ &session, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("Failed to start auth session (TPM2_StartAuthSession: 0x%x)"), rc);
++ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to start auth session (TPM2_StartAuthSession: 0x%x)", rc);
+
+ /* Enforce the policy command sequence */
-+ err = grub_tpm2_protector_enforce_policy_seq (policy_seq, session);
++ err = tpm2_protector_enforce_policy_seq (policy_seq, session);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ /* Unseal Sealed Key */
+ authCmd.sessionHandle = session;
-+ rc = TPM2_Unseal (sealed_handle, &authCmd, &data, NULL);
++ rc = grub_tpm2_unseal (sealed_handle, &authCmd, &data, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ err = grub_error (GRUB_ERR_BAD_DEVICE, N_("Failed to unseal sealed key (TPM2_Unseal: 0x%x)"), rc);
++ err = grub_error (GRUB_ERR_BAD_DEVICE, "Failed to unseal sealed key (TPM2_Unseal: 0x%x)", rc);
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ key_out = grub_malloc (data.size);
+ if (key_out == NULL)
+ {
-+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("No memory left to allocate unlock key buffer"));
++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "No memory left to allocate unlock key buffer");
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ err = GRUB_ERR_NONE;
+
+ error:
-+ TPM2_FlushContext (session);
++ grub_tpm2_flushcontext (session);
+
+ return err;
+}
+
+static grub_err_t
-+grub_tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx,
-+ grub_uint8_t **key, grub_size_t *key_size)
++tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx,
++ grub_uint8_t **key, grub_size_t *key_size)
+{
+ tpm2_sealed_key_t sealed_key = {0};
+ void *file_bytes = NULL;
+ grub_size_t file_size = 0;
+ grub_uint8_t rsaparent = 0;
-+ TPM_HANDLE parent_handle = 0;
-+ TPM_HANDLE srk_handle = 0;
-+ TPM_HANDLE sealed_handle = 0;
++ TPM_HANDLE_t parent_handle = 0;
++ TPM_HANDLE_t srk_handle = 0;
++ TPM_HANDLE_t sealed_handle = 0;
+ tpm2key_policy_t policy_seq = NULL;
+ tpm2key_authpolicy_t authpol = NULL;
+ tpm2key_authpolicy_t authpol_seq = NULL;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ */
+ if (ctx->tpm2key != NULL)
+ {
-+ err = grub_tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes,
++ err = tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes,
+ &file_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
-+ err = grub_tpm2_protector_srk_unmarshal_tpm2key (file_bytes,
-+ file_size,
-+ &policy_seq,
-+ &authpol_seq,
-+ &rsaparent,
-+ &parent_handle,
-+ &sealed_key);
++ err = tpm2_protector_srk_unmarshal_tpm2key (file_bytes,
++ file_size,
++ &policy_seq,
++ &authpol_seq,
++ &rsaparent,
++ &parent_handle,
++ &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ }
+ else
+ {
-+ err = grub_tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes,
-+ &file_size);
++ err = tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes, &file_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ parent_handle = TPM_RH_OWNER;
-+ err = grub_tpm2_protector_srk_unmarshal_keyfile (file_bytes,
-+ file_size,
-+ &sealed_key);
++ err = tpm2_protector_srk_unmarshal_keyfile (file_bytes, file_size, &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+ }
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ srk_handle = parent_handle;
+
+ /* Load the sealed key into TPM and associate it with the SRK */
-+ err = grub_tpm2_protector_load_key (ctx, &sealed_key, parent_handle,
-+ &sealed_handle, &srk_handle);
++ err = tpm2_protector_load_key (ctx, &sealed_key, parent_handle, &sealed_handle, &srk_handle);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ /* Iterate the authpolicy sequence to find one that unseals the key */
+ FOR_LIST_ELEMENTS (authpol, authpol_seq)
+ {
-+ err = grub_tpm2_protector_unseal (authpol->policy_seq, sealed_handle,
-+ key, key_size);
++ err = tpm2_protector_unseal (authpol->policy_seq, sealed_handle, key, key_size);
+ if (err == GRUB_ERR_NONE)
+ break;
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ */
+ if (policy_seq == NULL)
+ {
-+ err = grub_tpm2_protector_simple_policy_seq (ctx, &policy_seq);
++ err = tpm2_protector_simple_policy_seq (ctx, &policy_seq);
+ if (err != GRUB_ERR_NONE)
+ goto exit2;
+ }
+
-+ err = grub_tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size);
++ err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size);
+ }
+
+ /* Pop error messages on success */
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ while (grub_error_pop ());
+
+ exit2:
-+ TPM2_FlushContext (sealed_handle);
++ grub_tpm2_flushcontext (sealed_handle);
+
+ if (!TPM_HT_IS_PERSISTENT (srk_handle))
-+ TPM2_FlushContext (srk_handle);
++ grub_tpm2_flushcontext (srk_handle);
+
+ exit1:
+ grub_tpm2key_free_policy_seq (policy_seq);
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx __attribute__ ((unused)),
-+ grub_uint8_t **key __attribute__ ((unused)),
-+ grub_size_t *key_size __attribute__ ((unused)))
++tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx __attribute__ ((unused)),
++ grub_uint8_t **key __attribute__ ((unused)),
++ grub_size_t *key_size __attribute__ ((unused)))
+{
-+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, N_("NV Index mode is not implemented yet"));
++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "NV Index mode is not implemented yet");
+}
+
+static grub_err_t
-+grub_tpm2_protector_recover (const struct grub_tpm2_protector_context *ctx,
-+ grub_uint8_t **key, grub_size_t *key_size)
++tpm2_protector_recover (const struct grub_tpm2_protector_context *ctx,
++ grub_uint8_t **key, grub_size_t *key_size)
+{
+ switch (ctx->mode)
+ {
+ case GRUB_TPM2_PROTECTOR_MODE_SRK:
-+ return grub_tpm2_protector_srk_recover (ctx, key, key_size);
++ return tpm2_protector_srk_recover (ctx, key, key_size);
+ case GRUB_TPM2_PROTECTOR_MODE_NV:
-+ return grub_tpm2_protector_nv_recover (ctx, key, key_size);
++ return tpm2_protector_nv_recover (ctx, key, key_size);
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+}
+
+static grub_err_t
-+grub_tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t *key_size)
++tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t *key_size)
+{
+ /* Expect a call to tpm2_protector_init before anybody tries to use us */
+ if (grub_tpm2_protector_ctx.mode == GRUB_TPM2_PROTECTOR_MODE_UNSET)
-+ return grub_error (GRUB_ERR_INVALID_COMMAND, N_("Cannot use TPM2 key protector without initializing it, call tpm2_protector_init first"));
++ return grub_error (GRUB_ERR_INVALID_COMMAND, "Cannot use TPM2 key protector without initializing it, call tpm2_protector_init first");
+
+ if (key == NULL || key_size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
-+ return grub_tpm2_protector_recover (&grub_tpm2_protector_ctx, key, key_size);
++ return tpm2_protector_recover (&grub_tpm2_protector_ctx, key, key_size);
+}
+
+static grub_err_t
-+grub_tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx)
++tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx)
+{
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_UNSET)
+ ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ /* Checks for SRK mode */
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK &&
+ (ctx->keyfile == NULL && ctx->tpm2key == NULL))
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("In SRK mode, a key file must be specified: --tpm2key/-T or --keyfile/-k"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In SRK mode, a key file must be specified: --tpm2key/-T or --keyfile/-k");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK &&
+ (ctx->keyfile != NULL && ctx->tpm2key != NULL))
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("In SRK mode, please specify a key file with only --tpm2key/-T or --keyfile/-k"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In SRK mode, please specify a key file with only --tpm2key/-T or --keyfile/-k");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->nv != 0)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("In SRK mode, an NV Index cannot be specified"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In SRK mode, an NV Index cannot be specified");
+
+ /* Checks for NV mode */
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->nv == 0)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("In NV Index mode, an NV Index must be specified: --nvindex or -n"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, an NV Index must be specified: --nvindex or -n");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV &&
+ (ctx->tpm2key != NULL || ctx->keyfile != NULL))
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("In NV Index mode, a keyfile cannot be specified"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, a keyfile cannot be specified");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->srk != 0)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("In NV Index mode, an SRK cannot be specified"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, an SRK cannot be specified");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV &&
+ ctx->srk_type.type != TPM_ALG_ERROR)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("In NV Index mode, an asymmetric key type cannot be specified"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, an asymmetric key type cannot be specified");
+
+ /* Defaults assignment */
+ if (ctx->bank == TPM_ALG_ERROR)
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_parse_file (const char *value, const char **file)
++tpm2_protector_parse_file (const char *value, const char **file)
+{
+ if (grub_strlen (value) == 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *file = grub_strdup (value);
+ if (*file == NULL)
-+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("No memory to duplicate file path"));
++ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No memory to duplicate file path");
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
-+grub_tpm2_protector_parse_mode (const char *value,
-+ grub_tpm2_protector_mode_t *mode)
++tpm2_protector_parse_mode (const char *value, grub_tpm2_protector_mode_t *mode)
+{
+ if (grub_strcmp (value, "srk") == 0)
+ *mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+ else if (grub_strcmp (value, "nv") == 0)
+ *mode = GRUB_TPM2_PROTECTOR_MODE_NV;
+ else
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Value '%s' is not a valid TPM2 key protector mode"), value);
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid TPM2 key protector mode", value);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
-+grub_tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
-+ char **args __attribute__ ((unused)))
++tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
++ char **args __attribute__ ((unused)))
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_err_t err;
+
+ if (argc)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("The TPM2 key protector does not accept any non-option arguments (i.e., like -o and/or --option only)"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "The TPM2 key protector does not accept any non-option arguments (i.e., like -o and/or --option only)");
+
+ grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx));
+
+ if (state[OPTION_MODE].set) /* mode */
+ {
-+ err = grub_tpm2_protector_parse_mode (state[OPTION_MODE].arg,
-+ &grub_tpm2_protector_ctx.mode);
++ err = tpm2_protector_parse_mode (state[OPTION_MODE].arg, &grub_tpm2_protector_ctx.mode);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+
+ if (state[OPTION_TPM2KEY].set) /* tpm2key */
+ {
-+ err = grub_tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
-+ &grub_tpm2_protector_ctx.tpm2key);
++ err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
++ &grub_tpm2_protector_ctx.tpm2key);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_KEYFILE].set) /* keyfile */
+ {
-+ err = grub_tpm2_protector_parse_file (state[OPTION_KEYFILE].arg,
-+ &grub_tpm2_protector_ctx.keyfile);
++ err = tpm2_protector_parse_file (state[OPTION_KEYFILE].arg,
++ &grub_tpm2_protector_ctx.keyfile);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ return err;
+ }
+
-+ err = grub_tpm2_protector_check_args (&grub_tpm2_protector_ctx);
++ err = tpm2_protector_check_args (&grub_tpm2_protector_ctx);
+
+ /* This command only initializes the protector, so nothing else to do. */
+
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+}
+
+static grub_err_t
-+grub_tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt __attribute__ ((unused)),
-+ int argc,
-+ char **args __attribute__ ((unused)))
++tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt __attribute__ ((unused)),
++ int argc, char **args __attribute__ ((unused)))
+{
+ if (argc)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("tpm2_key_protector_clear accepts no arguments"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "tpm2_key_protector_clear accepts no arguments");
+
+ grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx));
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+static struct grub_key_protector grub_tpm2_key_protector =
+ {
+ .name = "tpm2",
-+ .recover_key = grub_tpm2_protector_recover_key
++ .recover_key = tpm2_protector_recover_key
+ };
+
+GRUB_MOD_INIT (tpm2_key_protector)
+{
+ grub_tpm2_protector_init_cmd =
+ grub_register_extcmd ("tpm2_key_protector_init",
-+ grub_tpm2_protector_init_cmd_handler, 0,
++ tpm2_protector_init_cmd_handler, 0,
+ N_("[-m mode] "
+ "[-p pcr_list] "
+ "[-b pcr_bank] "
@@ grub-core/commands/tpm2_key_protector/module.c (new)
+ grub_tpm2_protector_init_cmd_options);
+ grub_tpm2_protector_clear_cmd =
+ grub_register_extcmd ("tpm2_key_protector_clear",
-+ grub_tpm2_protector_clear_cmd_handler, 0, NULL,
++ tpm2_protector_clear_cmd_handler, 0, NULL,
+ N_("Clear the TPM2 key protector if previously initialized."),
+ NULL);
+ grub_key_protector_register (&grub_tpm2_key_protector);
@@ grub-core/commands/tpm2_key_protector/tpm2.h (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/commands/tpm2_key_protector/tpm2.h (new)
+#define TPM2_SRK_HANDLE 0x81000001
+
+struct tpm2_sealed_key {
-+ TPM2B_PUBLIC public;
-+ TPM2B_PRIVATE private;
++ TPM2B_PUBLIC_t public;
++ TPM2B_PRIVATE_t private;
+};
+typedef struct tpm2_sealed_key tpm2_sealed_key_t;
+
@@ grub-core/commands/tpm2_key_protector/tpm2_args.h (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2024 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
@@ grub-core/commands/tpm2_key_protector/tpm2_args.h (new)
+
+struct grub_srk_type
+{
-+ TPMI_ALG_PUBLIC type;
++ TPMI_ALG_PUBLIC_t type;
+ union {
-+ TPM_KEY_BITS rsa_bits;
-+ TPM_ECC_CURVE ecc_curve;
++ TPM_KEY_BITS_t rsa_bits;
++ TPM_ECC_CURVE_t ecc_curve;
+ } detail;
+};
+typedef struct grub_srk_type grub_srk_type_t;
+
+grub_err_t
-+grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs,
-+ grub_uint8_t *pcr_count);
++grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs, grub_uint8_t *pcr_count);
+
+grub_err_t
-+grub_tpm2_protector_parse_asymmetric (const char *value,
-+ grub_srk_type_t *srk_type);
++grub_tpm2_protector_parse_asymmetric (const char *value, grub_srk_type_t *srk_type);
+
+grub_err_t
-+grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID *bank);
++grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID_t *bank);
+
+grub_err_t
-+grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle);
++grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle);
+
+#endif /* ! GRUB_TPM2_INTERNAL_ARGS_HEADER */
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2023 SUSE LLC
++ * Copyright (C) 2024 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
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ */
+ ret = asn1_array2tree (tpm2key_asn1_tab, &tpm2key_asn1, NULL);
+ if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Failed to parse TPM2KEY ASN.1 array"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to parse TPM2KEY ASN.1 array");
+
+ ret = asn1_create_element (tpm2key_asn1, "TPM2KEY.TPMKey", &tpm2key);
+ if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Failed to create TPM2KEY.TPMKey"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to create TPM2KEY.TPMKey");
+
+ ret = asn1_der_decoding (&tpm2key, data, size, NULL);
+ if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Failed to decode TPM2KEY DER"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to decode TPM2KEY DER");
+
+ /* Check if 'type' is Sealed Key or not */
+ ret = asn1_allocate_and_read (tpm2key, "type", &type_oid, &type_oid_size);
+ if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("Not a valid TPM2KEY file"));
++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Not a valid TPM2KEY file");
+
+ if (grub_memcmp (sealed_key_oid, type_oid, type_oid_size) != 0)
+ {
-+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("Not a valid TPM2KEY file"));
++ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Not a valid TPM2KEY file");
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ ret = asn1_allocate_and_read (tpm2key, "emptyAuth", &empty_auth, &empty_auth_size);
+ if (ret != ASN1_SUCCESS || grub_strncmp ("TRUE", empty_auth, empty_auth_size) != 0)
+ {
-+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("emptyAuth not TRUE"));
++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "emptyAuth not TRUE");
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ ret = asn1_read_value (tpm2key, "secret", NULL, &tmp_size);
+ if (ret != ASN1_ELEMENT_NOT_FOUND)
+ {
-+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, N_("\"secret\" not allowed for Sealed Key"));
++ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "\"secret\" not allowed for Sealed Key");
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ int ret;
+
+ if (rsaparent == NULL)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer detected"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "NULL pointer detected");
+
+ if (tpm2key == NULL)
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Invalid parent node"));
++ return grub_error (GRUB_ERR_READ_ERROR, "Invalid parent node");
+
+ ret = asn1_allocate_and_read (tpm2key, "rsaParent", &bool_str, &bool_str_size);
+ if (ret == ASN1_SUCCESS)
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ else if (ret == ASN1_ELEMENT_NOT_FOUND)
+ *rsaparent = 0;
+ else
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve rsaParent"));
++ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve rsaParent");
+
+ grub_free (bool_str);
+
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ int ret;
+
+ if (parent == NULL)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("NULL pointer detected"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "NULL pointer detected");
+
+ if (tpm2key == NULL)
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Invalid parent node"));
++ return grub_error (GRUB_ERR_READ_ERROR, "Invalid parent node");
+
+ ret = asn1_read_uint32 (tpm2key, "parent", parent);
+ if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve parent"));
++ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve parent");
+
+ return GRUB_ERR_NONE;
+}
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ int ret;
+
+ if (name == NULL || data == NULL || size == NULL)
-+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Invalid parameter(s)"));
++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid parameter(s)");
+
+ if (tpm2key == NULL)
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Invalid %s node"), name);
++ return grub_error (GRUB_ERR_READ_ERROR, "Invalid %s node", name);
+
+ ret = asn1_allocate_and_read (tpm2key, name, data, size);
+ if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve %s"), name);
++ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve %s", name);
+
+ return GRUB_ERR_NONE;
+}
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ return GRUB_ERR_NONE;
+ }
+ else if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve policy"));
++ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve policy");
+
+ return GRUB_ERR_NONE;
+}
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ return GRUB_ERR_NONE;
+ }
+ else if (ret != ASN1_SUCCESS)
-+ return grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve authPolicy"));
++ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve authPolicy");
+
+ /* Limit the number of authPolicy elements to two digits (99) */
+ if (authpol_n > TPM2KEY_ELEMENTS_MAX || authpol_n < TPM2KEY_ELEMENTS_MIN)
-+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Invalid number of authPolicy elements"));
++ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid number of authPolicy elements");
+
+ /*
+ * Iterate the authPolicy elements backwards since grub_list_push() prepends
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ authpol = grub_zalloc (sizeof (struct tpm2key_authpolicy));
+ if (authpol == NULL)
+ {
-+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Failed to allocate memory for authPolicy"));
++ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Failed to allocate memory for authPolicy");
+ goto error;
+ }
+ grub_snprintf (authpol_pol, AUTHPOLICY_POL_MAX, "authPolicy.?%d.Policy", i);
@@ grub-core/commands/tpm2_key_protector/tpm2key.c (new)
+ ret = tpm2key_get_policy_seq (tpm2key, authpol_pol, &authpol->policy_seq);
+ if (ret != ASN1_SUCCESS)
+ {
-+ err = grub_error (GRUB_ERR_READ_ERROR, N_("Failed to retrieve policy from authPolicy"));
++ err = grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve policy from authPolicy");
+ goto error;
+ }
+
@@ grub-core/commands/tpm2_key_protector/tpm2key.h (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2023 SUSE LLC
++ * Copyright (C) 2024 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
17: 5e8d2abed ! 23: 9f346b58e cryptodisk: Support key protectors
@@ Commit message
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
## Makefile.util.def ##
@@ Makefile.util.def: library = {
@@ include/grub/cryptodisk.h: typedef gcry_err_code_t
+ * The key protector associated with this cache entry failed, so avoid it
+ * even if the cached entry (an instance of this structure) is empty.
+ */
-+ int invalid;
++ bool invalid;
+};
+
struct grub_cryptomount_args
18: 37c33fa02 ! 24: 08eab00ac util/grub-protect: Add new tool
@@ docs/man/grub-protect.h2m (new)
+[NAME]
+grub-protect \- protect a disk key with a key protector
+[DESCRIPTION]
-+grub-protect helps to pretect a disk encryption key with a specified key protector.
++grub-protect helps to protect a disk encryption key with a specified key protector.
## util/grub-protect.c (new) ##
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
-+ * Copyright (C) 2023 SUSE LLC
+ * Copyright (C) 2022 Microsoft Corporation
++ * Copyright (C) 2023 SUSE LLC
++ * Copyright (C) 2024 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
@@ util/grub-protect.c (new)
+ grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS];
+ grub_uint8_t tpm2_pcr_count;
+ grub_srk_type_t srk_type;
-+ TPM_ALG_ID tpm2_bank;
-+ TPM_HANDLE tpm2_srk;
++ TPM_ALG_ID_t tpm2_bank;
++ TPM_HANDLE_t tpm2_srk;
+ const char *tpm2_keyfile;
+ const char *tpm2_outfile;
+ int tpm2_evict;
@@ util/grub-protect.c (new)
+ .arg = "tpm2",
+ .flags = 0,
+ .doc =
-+ N_("Key protector to use (only tpm2 is currently supported)."),
++ N_("Set key protector to use (only tpm2 is currently supported)."),
+ .group = 0
+ },
+ /* TPM2 key protector options */
@@ util/grub-protect.c (new)
+ .arg = "FILE",
+ .flags = 0,
+ .doc =
-+ N_("Path to the TPM2 device. (default: /dev/tpm0)"),
++ N_("Set the path to the TPM2 device. (default: /dev/tpm0)"),
+ .group = 0
+ },
+ {
@@ util/grub-protect.c (new)
+ .arg = "0[,1]...",
+ .flags = 0,
+ .doc =
-+ N_("Comma-separated list of PCRs used to authorize key release "
++ N_("Set a comma-separated list of PCRs used to authorize key release "
+ "e.g., '7,11'. Please be aware that PCR 0~7 are used by the "
+ "firmware and the measurement result may change after a "
+ "firmware update (for baremetal systems) or a package "
-+ "(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to"
++ "(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to "
+ "the failure of key unsealing. (default: 7)"),
+ .group = 0
+ },
@@ util/grub-protect.c (new)
+ .arg = "ALG",
+ .flags = 0,
+ .doc =
-+ N_("Bank of PCRs used to authorize key release: "
++ N_("Set the bank of PCRs used to authorize key release: "
+ "SHA1, SHA256, SHA384, or SHA512. (default: SHA256)"),
+ .group = 0
+ },
@@ util/grub-protect.c (new)
+ .arg = "FILE",
+ .flags = 0,
+ .doc =
-+ N_("Path to a file that contains the cleartext key to protect."),
++ N_("Set the path to a file that contains the cleartext key to protect."),
+ .group = 0
+ },
+ {
@@ util/grub-protect.c (new)
+ .arg = "FILE",
+ .flags = 0,
+ .doc =
-+ N_("Path to the file that will contain the key after sealing (must be "
-+ "accessible to GRUB during boot)."),
++ N_("Set the path to the file that will contain the key after sealing "
++ "(must be accessible to GRUB during boot)."),
+ .group = 0
+ },
+ {
@@ util/grub-protect.c (new)
+ .arg = "NUM",
+ .flags = 0,
+ .doc =
-+ N_("The SRK handle if the SRK is to be made persistent."),
++ N_("Set the SRK handle if the SRK is to be made persistent."),
+ .group = 0
+ },
+ {
@@ util/grub-protect.c (new)
+ .arg = "TYPE",
+ .flags = 0,
+ .doc =
-+ N_("The type of SRK: RSA (RSA2048) and ECC (ECC_NIST_P256)."
++ N_("Set the type of SRK: RSA (RSA2048) and ECC (ECC_NIST_P256)."
+ "(default: ECC)"),
+ .group = 0
+ },
@@ util/grub-protect.c (new)
+ { 0, 0, 0, 0, 0, 0 }
+ };
+
-+static int grub_protector_tpm2_fd = -1;
++static int protector_tpm2_fd = -1;
+
+static grub_err_t
-+grub_protect_read_file (const char *filepath, void **buffer,
-+ size_t *buffer_size)
++protect_read_file (const char *filepath, void **buffer, size_t *buffer_size)
+{
+ grub_err_t err;
+ FILE *f;
@@ util/grub-protect.c (new)
+ buf = NULL;
+ err = GRUB_ERR_NONE;
+
-+exit2:
++ exit2:
+ grub_free (buf);
+
-+exit1:
++ exit1:
+ fclose (f);
+
+ return err;
+}
+
+static grub_err_t
-+grub_protect_write_file (const char *filepath, void *buffer, size_t buffer_size)
++protect_write_file (const char *filepath, void *buffer, size_t buffer_size)
+{
+ grub_err_t err;
+ FILE *f;
@@ util/grub-protect.c (new)
+
+ err = GRUB_ERR_NONE;
+
-+exit1:
++ exit1:
+ fclose (f);
+
+ return err;
@@ util/grub-protect.c (new)
+ static const grub_size_t header_size = sizeof (grub_uint16_t) +
+ (2 * sizeof(grub_uint32_t));
+
-+ if (write (grub_protector_tpm2_fd, input, input_size) != input_size)
++ if (write (protector_tpm2_fd, input, input_size) != input_size)
+ return GRUB_ERR_BAD_DEVICE;
+
-+ if (read (grub_protector_tpm2_fd, output, output_size) < header_size)
++ if (read (protector_tpm2_fd, output, output_size) < header_size)
+ return GRUB_ERR_BAD_DEVICE;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
-+grub_protect_tpm2_open_device (const char *dev_node)
++protect_tpm2_open_device (const char *dev_node)
+{
-+ if (grub_protector_tpm2_fd != -1)
++ if (protector_tpm2_fd != -1)
+ return GRUB_ERR_NONE;
+
-+ grub_protector_tpm2_fd = open (dev_node, O_RDWR);
-+ if (grub_protector_tpm2_fd == -1)
++ protector_tpm2_fd = open (dev_node, O_RDWR);
++ if (protector_tpm2_fd == -1)
+ {
-+ fprintf (stderr, _("Could not open TPM device (%s).\n"), strerror (errno));
++ fprintf (stderr, "Could not open TPM device (%s).\n", strerror (errno));
+ return GRUB_ERR_FILE_NOT_FOUND;
+ }
+
@@ util/grub-protect.c (new)
+}
+
+static grub_err_t
-+grub_protect_tpm2_close_device (void)
++protect_tpm2_close_device (void)
+{
+ int err;
+
-+ if (grub_protector_tpm2_fd == -1)
++ if (protector_tpm2_fd == -1)
+ return GRUB_ERR_NONE;
+
-+ err = close (grub_protector_tpm2_fd);
++ err = close (protector_tpm2_fd);
+ if (err != GRUB_ERR_NONE)
+ {
-+ fprintf (stderr, _("Could not close TPM device (Error: %u).\n"), errno);
++ fprintf (stderr, "Could not close TPM device (Error: %u).\n", errno);
+ return GRUB_ERR_IO;
+ }
+
-+ grub_protector_tpm2_fd = -1;
++ protector_tpm2_fd = -1;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
-+grub_protect_tpm2_get_policy_digest (struct grub_protect_args *args,
-+ TPM2B_DIGEST *digest)
++protect_tpm2_get_policy_digest (struct grub_protect_args *args, TPM2B_DIGEST_t *digest)
+{
-+ TPM_RC rc;
-+ TPML_PCR_SELECTION pcr_sel = {
++ TPM_RC_t rc;
++ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
@@ util/grub-protect.c (new)
+ },
+ }
+ };
-+ TPML_PCR_SELECTION pcr_sel_out = { 0 };
-+ TPML_DIGEST pcr_values = { 0 };
-+ TPM2B_DIGEST pcr_digest = { 0 };
++ TPML_PCR_SELECTION_t pcr_sel_out = { 0 };
++ TPML_DIGEST_t pcr_values = { 0 };
++ TPM2B_DIGEST_t pcr_digest = { 0 };
+ grub_size_t pcr_digest_len;
-+ TPM2B_MAX_BUFFER pcr_concat = { 0 };
++ TPM2B_MAX_BUFFER_t pcr_concat = { 0 };
+ grub_size_t pcr_concat_len;
+ grub_uint8_t *pcr_cursor;
-+ TPM2B_NONCE nonce = { 0 };
-+ TPM2B_ENCRYPTED_SECRET salt = { 0 };
-+ TPMT_SYM_DEF symmetric = { 0 };
-+ TPMI_SH_AUTH_SESSION session = 0;
-+ TPM2B_DIGEST policy_digest = { 0 };
++ TPM2B_NONCE_t nonce = { 0 };
++ TPM2B_ENCRYPTED_SECRET_t salt = { 0 };
++ TPMT_SYM_DEF_t symmetric = { 0 };
++ TPMI_SH_AUTH_SESSION_t session = 0;
++ TPM2B_DIGEST_t policy_digest = { 0 };
+ grub_uint8_t i;
+ grub_err_t err;
+
@@ util/grub-protect.c (new)
+ for (i = 0; i < args->tpm2_pcr_count; i++)
+ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], args->tpm2_pcrs[i]);
+
-+ rc = TPM2_PCR_Read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL);
++ rc = grub_tpm2_pcr_read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to read PCRs (TPM2_PCR_Read: 0x%x).\n"), rc);
++ fprintf (stderr, "Failed to read PCRs (TPM2_PCR_Read: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
@@ util/grub-protect.c (new)
+ (pcr_sel.pcrSelections[0].sizeOfSelect !=
+ pcr_sel_out.pcrSelections[0].sizeOfSelect))
+ {
-+ fprintf (stderr, _("Could not read all the specified PCRs.\n"));
++ fprintf (stderr, "Could not read all the specified PCRs.\n");
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
@@ util/grub-protect.c (new)
+ pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count;
+ if (pcr_concat_len > TPM_MAX_DIGEST_BUFFER)
+ {
-+ fprintf (stderr, _("PCR concatenation buffer not enough.\n"));
++ fprintf (stderr, "PCR concatenation buffer not enough.\n");
+ return GRUB_ERR_OUT_OF_RANGE;
+ }
+
@@ util/grub-protect.c (new)
+ if (pcr_values.digests[i].size != pcr_digest_len)
+ {
+ fprintf (stderr,
-+ _("Bad PCR value size: expected %" PRIuGRUB_SIZE " bytes but got %u bytes.\n"),
++ "Bad PCR value size: expected %" PRIuGRUB_SIZE " bytes but got %u bytes.\n",
+ pcr_digest_len, pcr_values.digests[i].size);
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
@@ util/grub-protect.c (new)
+ }
+ pcr_concat.size = pcr_concat_len;
+
-+ rc = TPM2_Hash (NULL, &pcr_concat, args->tpm2_bank, TPM_RH_NULL, &pcr_digest,
-+ NULL, NULL);
++ rc = grub_tpm2_hash (NULL, &pcr_concat, args->tpm2_bank, TPM_RH_NULL, &pcr_digest, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to generate PCR digest (TPM2_Hash: 0x%x)\n"), rc);
++ fprintf (stderr, "Failed to generate PCR digest (TPM2_Hash: 0x%x)\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
@@ util/grub-protect.c (new)
+ nonce.size = TPM_SHA256_DIGEST_SIZE;
+ symmetric.algorithm = TPM_ALG_NULL;
+
-+ rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonce, &salt,
-+ TPM_SE_TRIAL, &symmetric, TPM_ALG_SHA256,
-+ &session, NULL, 0);
++ rc = grub_tpm2_startauthsession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonce, &salt,
++ TPM_SE_TRIAL, &symmetric, TPM_ALG_SHA256,
++ &session, NULL, 0);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr,
-+ _("Failed to start trial policy session (TPM2_StartAuthSession: 0x%x).\n"),
-+ rc);
++ fprintf (stderr, "Failed to start trial policy session (TPM2_StartAuthSession: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* PCR Policy */
-+ rc = TPM2_PolicyPCR (session, NULL, &pcr_digest, &pcr_sel, NULL);
++ rc = grub_tpm2_policypcr (session, NULL, &pcr_digest, &pcr_sel, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x).\n"),
-+ rc);
++ fprintf (stderr, "Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x).\n", rc);
+ err = GRUB_ERR_BAD_DEVICE;
+ goto error;
+ }
+
+ /* Retrieve Policy Digest */
-+ rc = TPM2_PolicyGetDigest (session, NULL, &policy_digest, NULL);
++ rc = grub_tpm2_policygetdigest (session, NULL, &policy_digest, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to get policy digest (TPM2_PolicyGetDigest: 0x%x).\n"),
-+ rc);
++ fprintf (stderr, "Failed to get policy digest (TPM2_PolicyGetDigest: 0x%x).\n", rc);
+ err = GRUB_ERR_BAD_DEVICE;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ *digest = policy_digest;
+ err = GRUB_ERR_NONE;
+
-+error:
-+ TPM2_FlushContext (session);
++ error:
++ grub_tpm2_flushcontext (session);
+
+ return err;
+}
+
+static grub_err_t
-+grub_protect_tpm2_get_srk (struct grub_protect_args *args, TPM_HANDLE *srk)
++protect_tpm2_get_srk (struct grub_protect_args *args, TPM_HANDLE_t *srk)
+{
-+ TPM_RC rc;
-+ TPM2B_PUBLIC public;
-+ TPMS_AUTH_COMMAND authCommand = { 0 };
-+ TPM2B_SENSITIVE_CREATE inSensitive = { 0 };
-+ TPM2B_PUBLIC inPublic = { 0 };
-+ TPM2B_DATA outsideInfo = { 0 };
-+ TPML_PCR_SELECTION creationPcr = { 0 };
-+ TPM2B_PUBLIC outPublic = { 0 };
-+ TPM2B_CREATION_DATA creationData = { 0 };
-+ TPM2B_DIGEST creationHash = { 0 };
-+ TPMT_TK_CREATION creationTicket = { 0 };
-+ TPM2B_NAME srkName = { 0 };
-+ TPM_HANDLE srkHandle;
++ TPM_RC_t rc;
++ TPM2B_PUBLIC_t public;
++ TPMS_AUTH_COMMAND_t authCommand = { 0 };
++ TPM2B_SENSITIVE_CREATE_t inSensitive = { 0 };
++ TPM2B_PUBLIC_t inPublic = { 0 };
++ TPM2B_DATA_t outsideInfo = { 0 };
++ TPML_PCR_SELECTION_t creationPcr = { 0 };
++ TPM2B_PUBLIC_t outPublic = { 0 };
++ TPM2B_CREATION_DATA_t creationData = { 0 };
++ TPM2B_DIGEST_t creationHash = { 0 };
++ TPMT_TK_CREATION_t creationTicket = { 0 };
++ TPM2B_NAME_t srkName = { 0 };
++ TPM_HANDLE_t srkHandle;
+
+ if (args->tpm2_srk != 0)
+ {
+ /* Find SRK */
-+ rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public);
++ rc = grub_tpm2_readpublic (args->tpm2_srk, NULL, &public);
+ if (rc == TPM_RC_SUCCESS)
+ {
-+ printf (_("Read SRK from 0x%x\n"), args->tpm2_srk);
++ printf ("Read SRK from 0x%x\n", args->tpm2_srk);
+ *srk = args->tpm2_srk;
+ return GRUB_ERR_NONE;
+ }
@@ util/grub-protect.c (new)
+ /* The handle exists but its public area could not be read. */
+ if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE)
+ {
-+ fprintf (stderr,
-+ _("Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x).\n"),
-+ args->tpm2_srk, rc);
++ fprintf (stderr, "Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x).\n", args->tpm2_srk, rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+ }
@@ util/grub-protect.c (new)
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
-+ rc = TPM2_CreatePrimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic,
-+ &outsideInfo, &creationPcr, &srkHandle, &outPublic,
-+ &creationData, &creationHash, &creationTicket,
-+ &srkName, NULL);
++ rc = grub_tpm2_createprimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic,
++ &outsideInfo, &creationPcr, &srkHandle, &outPublic,
++ &creationData, &creationHash, &creationTicket,
++ &srkName, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to create SRK (TPM2_CreatePrimary: 0x%x).\n"), rc);
++ fprintf (stderr, "Failed to create SRK (TPM2_CreatePrimary: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Persist SRK */
+ if (args->tpm2_srk != 0)
+ {
-+ rc = TPM2_EvictControl (TPM_RH_OWNER, srkHandle, &authCommand,
-+ args->tpm2_srk, NULL);
++ rc = grub_tpm2_evictcontrol (TPM_RH_OWNER, srkHandle, &authCommand, args->tpm2_srk, NULL);
+ if (rc == TPM_RC_SUCCESS)
+ {
-+ TPM2_FlushContext (srkHandle);
++ grub_tpm2_flushcontext (srkHandle);
+ srkHandle = args->tpm2_srk;
+ }
+ else
+ fprintf (stderr,
-+ _("Warning: Failed to persist SRK (0x%x) (TPM2_EvictControl: 0x%x\n). "
-+ "Continuing anyway...\n"), args->tpm2_srk, rc);
++ "Warning: Failed to persist SRK (0x%x) (TPM2_EvictControl: 0x%x).\n"
++ "Continuing anyway...\n", args->tpm2_srk, rc);
+ }
+
+ /* Epilogue */
@@ util/grub-protect.c (new)
+}
+
+static grub_err_t
-+grub_protect_tpm2_seal (TPM2B_DIGEST *policyDigest, TPM_HANDLE srk,
-+ grub_uint8_t *clearText, grub_size_t clearTextLength,
-+ tpm2_sealed_key_t *sealed_key)
++protect_tpm2_seal (TPM2B_DIGEST_t *policyDigest, TPM_HANDLE_t srk,
++ grub_uint8_t *clearText, grub_size_t clearTextLength,
++ tpm2_sealed_key_t *sealed_key)
+{
-+ TPM_RC rc;
-+ TPMS_AUTH_COMMAND authCommand = { 0 };
-+ TPM2B_SENSITIVE_CREATE inSensitive = { 0 };
-+ TPM2B_PUBLIC inPublic = { 0 };
-+ TPM2B_DATA outsideInfo = { 0 };
-+ TPML_PCR_SELECTION pcr_sel = { 0 };
-+ TPM2B_PRIVATE outPrivate = { 0 };
-+ TPM2B_PUBLIC outPublic = { 0 };
++ TPM_RC_t rc;
++ TPMS_AUTH_COMMAND_t authCommand = { 0 };
++ TPM2B_SENSITIVE_CREATE_t inSensitive = { 0 };
++ TPM2B_PUBLIC_t inPublic = { 0 };
++ TPM2B_DATA_t outsideInfo = { 0 };
++ TPML_PCR_SELECTION_t pcr_sel = { 0 };
++ TPM2B_PRIVATE_t outPrivate = { 0 };
++ TPM2B_PUBLIC_t outPublic = { 0 };
+
+ /* Seal Data */
+ authCommand.sessionHandle = TPM_RS_PW;
@@ util/grub-protect.c (new)
+ inPublic.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
+ inPublic.publicArea.authPolicy = *policyDigest;
+
-+ rc = TPM2_Create (srk, &authCommand, &inSensitive, &inPublic, &outsideInfo,
-+ &pcr_sel, &outPrivate, &outPublic, NULL, NULL, NULL, NULL);
++ rc = grub_tpm2_create (srk, &authCommand, &inSensitive, &inPublic, &outsideInfo,
++ &pcr_sel, &outPrivate, &outPublic, NULL, NULL, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to seal key (TPM2_Create: 0x%x).\n"), rc);
++ fprintf (stderr, "Failed to seal key (TPM2_Create: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
@@ util/grub-protect.c (new)
+extern asn1_static_node tpm2key_asn1_tab[];
+
+static grub_err_t
-+grub_protect_tpm2_export_tpm2key (const struct grub_protect_args *args,
-+ tpm2_sealed_key_t *sealed_key)
++protect_tpm2_export_tpm2key (const struct grub_protect_args *args,
++ tpm2_sealed_key_t *sealed_key)
+{
+ const char *sealed_key_oid = "2.23.133.10.1.5";
+ asn1_node asn1_def = NULL;
@@ util/grub-protect.c (new)
+ grub_uint32_t parent;
+ grub_uint32_t cmd_code;
+ struct grub_tpm2_buffer pol_buf;
-+ TPML_PCR_SELECTION pcr_sel = {
++ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "type", sealed_key_oid, 1);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'type': 0x%u\n"), ret);
++ fprintf (stderr, "Failed to set 'type': 0x%u\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "emptyAuth", "TRUE", 1);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'emptyAuth': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'emptyAuth': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "policy", "NEW", 1);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'policy': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'policy': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ sizeof (cmd_code));
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'policy CommandCode': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'policy CommandCode': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ pol_buf.size);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'policy CommandPolicy': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'policy CommandPolicy': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "secret", NULL, 0);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to remove 'secret': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to remove 'secret': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "authPolicy", NULL, 0);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to remove 'authPolicy': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to remove 'authPolicy': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "description", NULL, 0);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to remove 'description': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to remove 'description': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "parent", &parent, sizeof (parent));
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'parent': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'parent': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'rsaParent': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'rsaParent': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "pubkey", pub_buf.data, pub_buf.size);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'pubkey': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'pubkey': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_write_value (tpm2key, "privkey", priv_buf.data, priv_buf.size);
+ if (ret != ASN1_SUCCESS)
+ {
-+ fprintf (stderr, _("Failed to set 'privkey': 0x%x\n"), ret);
++ fprintf (stderr, "Failed to set 'privkey': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ ret = asn1_der_coding (tpm2key, "", NULL, &der_buf_size, NULL);
+ if (ret != ASN1_MEM_ERROR)
+ {
-+ fprintf (stderr, _("Failed to get DER size: 0x%x\n"), ret);
++ fprintf (stderr, "Failed to get DER size: 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ der_buf = grub_malloc (der_buf_size);
+ if (der_buf == NULL)
+ {
-+ fprintf (stderr, _("Failed to allocate memory for DER encoding\n"));
++ fprintf (stderr, "Failed to allocate memory for DER encoding\n");
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ goto error;
+ }
@@ util/grub-protect.c (new)
+ goto error;
+ }
+
-+ err = grub_protect_write_file (args->tpm2_outfile, der_buf, der_buf_size);
++ err = protect_write_file (args->tpm2_outfile, der_buf, der_buf_size);
+ if (err != GRUB_ERR_NONE)
-+ fprintf (stderr, _("Could not write tpm2key file (Error: %u).\n"),
-+ errno);
++ fprintf (stderr, "Could not write tpm2key file (Error: %u).\n", errno);
+
+ error:
+ grub_free (der_buf);
@@ util/grub-protect.c (new)
+}
+
+static grub_err_t
-+grub_protect_tpm2_export_sealed_key (const char *filepath,
-+ tpm2_sealed_key_t *sealed_key)
++protect_tpm2_export_sealed_key (const char *filepath,
++ tpm2_sealed_key_t *sealed_key)
+{
+ grub_err_t err;
+ struct grub_tpm2_buffer buf;
@@ util/grub-protect.c (new)
+ if (buf.error != 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
-+ err = grub_protect_write_file (filepath, buf.data, buf.size);
++ err = protect_write_file (filepath, buf.data, buf.size);
+ if (err != GRUB_ERR_NONE)
-+ fprintf (stderr, _("Could not write sealed key file (Error: %u).\n"),
-+ errno);
++ fprintf (stderr, "Could not write sealed key file (Error: %u).\n", errno);
+
+ return err;
+}
+
+static grub_err_t
-+grub_protect_tpm2_add (struct grub_protect_args *args)
++protect_tpm2_add (struct grub_protect_args *args)
+{
+ grub_err_t err;
+ grub_uint8_t *key = NULL;
+ grub_size_t key_size;
-+ TPM_HANDLE srk;
-+ TPM2B_DIGEST policy_digest;
++ TPM_HANDLE_t srk;
++ TPM2B_DIGEST_t policy_digest;
+ tpm2_sealed_key_t sealed_key;
+
-+ err = grub_protect_tpm2_open_device (args->tpm2_device);
++ err = protect_tpm2_open_device (args->tpm2_device);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
-+ err = grub_protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size);
++ err = protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+
+ if (key_size > TPM_MAX_SYM_DATA)
+ {
-+ fprintf (stderr,
-+ _("Input key is too long, maximum allowed size is %u bytes.\n"),
-+ TPM_MAX_SYM_DATA);
++ fprintf (stderr, "Input key size larger than %u bytes.\n", TPM_MAX_SYM_DATA);
+ err = GRUB_ERR_OUT_OF_RANGE;
+ goto exit2;
+ }
+
-+ err = grub_protect_tpm2_get_srk (args, &srk);
++ err = protect_tpm2_get_srk (args, &srk);
+ if (err != GRUB_ERR_NONE)
+ goto exit2;
+
-+ err = grub_protect_tpm2_get_policy_digest (args, &policy_digest);
++ err = protect_tpm2_get_policy_digest (args, &policy_digest);
+ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
-+ err = grub_protect_tpm2_seal (&policy_digest, srk, key, key_size,
-+ &sealed_key);
++ err = protect_tpm2_seal (&policy_digest, srk, key, key_size, &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ if (args->tpm2_tpm2key != 0)
-+ err = grub_protect_tpm2_export_tpm2key (args, &sealed_key);
++ err = protect_tpm2_export_tpm2key (args, &sealed_key);
+ else
-+ err = grub_protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key);
++ err = protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ exit3:
-+ TPM2_FlushContext (srk);
++ grub_tpm2_flushcontext (srk);
+
+ exit2:
+ grub_free (key);
+
+ exit1:
-+ grub_protect_tpm2_close_device ();
++ protect_tpm2_close_device ();
+
+ return err;
+}
+
+static grub_err_t
-+grub_protect_tpm2_remove (struct grub_protect_args *args)
++protect_tpm2_remove (struct grub_protect_args *args)
+{
-+ TPM_RC rc;
-+ TPM2B_PUBLIC public;
-+ TPMS_AUTH_COMMAND authCommand = { 0 };
++ TPM_RC_t rc;
++ TPM2B_PUBLIC_t public;
++ TPMS_AUTH_COMMAND_t authCommand = { 0 };
+ grub_err_t err;
+
+ if (args->tpm2_evict == 0)
+ {
-+ printf (_("--tpm2-evict not specified, nothing to do.\n"));
++ printf ("--tpm2-evict not specified, nothing to do.\n");
+ return GRUB_ERR_NONE;
+ }
+
-+ err = grub_protect_tpm2_open_device (args->tpm2_device);
++ err = protect_tpm2_open_device (args->tpm2_device);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /* Find SRK */
-+ rc = TPM2_ReadPublic (args->tpm2_srk, NULL, &public);
++ rc = grub_tpm2_readpublic (args->tpm2_srk, NULL, &public);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr, _("SRK with handle 0x%x not found.\n"), args->tpm2_srk);
++ fprintf (stderr, "SRK with handle 0x%x not found.\n", args->tpm2_srk);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto exit1;
+ }
@@ util/grub-protect.c (new)
+ /* Evict SRK */
+ authCommand.sessionHandle = TPM_RS_PW;
+
-+ rc = TPM2_EvictControl (TPM_RH_OWNER, args->tpm2_srk, &authCommand,
-+ args->tpm2_srk, NULL);
++ rc = grub_tpm2_evictcontrol (TPM_RH_OWNER, args->tpm2_srk, &authCommand, args->tpm2_srk, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
-+ fprintf (stderr,
-+ _("Failed to evict SRK with handle 0x%x (TPM2_EvictControl: 0x%x).\n"),
-+ args->tpm2_srk, rc);
++ fprintf (stderr, "Failed to evict SRK with handle 0x%x (TPM2_EvictControl: 0x%x).\n", args->tpm2_srk, rc);
+ err = GRUB_ERR_BAD_DEVICE;
+ goto exit2;
+ }
@@ util/grub-protect.c (new)
+ err = GRUB_ERR_NONE;
+
+ exit2:
-+ TPM2_FlushContext (args->tpm2_srk);
++ grub_tpm2_flushcontext (args->tpm2_srk);
+
+ exit1:
-+ grub_protect_tpm2_close_device ();
++ protect_tpm2_close_device ();
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
-+grub_protect_tpm2_run (struct grub_protect_args *args)
++protect_tpm2_run (struct grub_protect_args *args)
+{
+ switch (args->action)
+ {
+ case GRUB_PROTECT_ACTION_ADD:
-+ return grub_protect_tpm2_add (args);
++ return protect_tpm2_add (args);
+
+ case GRUB_PROTECT_ACTION_REMOVE:
-+ return grub_protect_tpm2_remove (args);
++ return protect_tpm2_remove (args);
+
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
@@ util/grub-protect.c (new)
+}
+
+static grub_err_t
-+grub_protect_tpm2_args_verify (struct grub_protect_args *args)
++protect_tpm2_args_verify (struct grub_protect_args *args)
+{
+ switch (args->action)
+ {
+ case GRUB_PROTECT_ACTION_ADD:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT)
+ {
-+ fprintf (stderr,
-+ _("--tpm2-evict is invalid when --action is 'add'.\n"));
++ fprintf (stderr, N_("--tpm2-evict is invalid when --action is 'add'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_keyfile == NULL)
+ {
-+ fprintf (stderr, _("--tpm2-keyfile must be specified.\n"));
++ fprintf (stderr, N_("--tpm2-keyfile must be specified.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_outfile == NULL)
+ {
-+ fprintf (stderr, _("--tpm2-outfile must be specified.\n"));
++ fprintf (stderr, N_("--tpm2-outfile must be specified.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_ACTION_REMOVE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC)
+ {
-+ fprintf (stderr,
-+ _("--tpm2-asymmetric is invalid when --action is 'remove'.\n"));
++ fprintf (stderr, N_("--tpm2-asymmetric is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK)
+ {
-+ fprintf (stderr,
-+ _("--tpm2-bank is invalid when --action is 'remove'.\n"));
++ fprintf (stderr, N_("--tpm2-bank is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE)
+ {
-+ fprintf (stderr,
-+ _("--tpm2-keyfile is invalid when --action is 'remove'.\n"));
++ fprintf (stderr, N_("--tpm2-keyfile is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE)
+ {
-+ fprintf (stderr,
-+ _("--tpm2-outfile is invalid when --action is 'remove'.\n"));
++ fprintf (stderr, N_("--tpm2-outfile is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS)
+ {
-+ fprintf (stderr,
-+ _("--tpm2-pcrs is invalid when --action is 'remove'.\n"));
++ fprintf (stderr, N_("--tpm2-pcrs is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_srk == 0)
+ {
-+ fprintf (stderr,
-+ _("--tpm2-srk is not specified when --action is 'remove'.\n"));
++ fprintf (stderr, N_("--tpm2-srk is not specified when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
@@ util/grub-protect.c (new)
+ break;
+
+ default:
-+ fprintf (stderr,
-+ _("The TPM2 key protector only supports the following actions: "
-+ "add, remove.\n"));
++ fprintf (stderr, N_("The TPM2 key protector only supports the following actions: add, remove.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
@@ util/grub-protect.c (new)
+}
+
+static error_t
-+grub_protect_argp_parser (int key, char *arg, struct argp_state *state)
++protect_argp_parser (int key, char *arg, struct argp_state *state)
+{
+ grub_err_t err;
+ struct grub_protect_args *args = state->input;
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_ACTION:
+ if (args->args & GRUB_PROTECT_ARG_ACTION)
+ {
-+ fprintf (stderr, _("--action|-a can only be specified once.\n"));
++ fprintf (stderr, N_("--action|-a can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ args->action = GRUB_PROTECT_ACTION_REMOVE;
+ else
+ {
-+ fprintf (stderr, _("'%s' is not a valid action.\n"), arg);
++ fprintf (stderr, N_("'%s' is not a valid action.\n"), arg);
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_PROTECTOR:
+ if (args->args & GRUB_PROTECT_ARG_PROTECTOR)
+ {
-+ fprintf (stderr, _("--protector|-p can only be specified once.\n"));
++ fprintf (stderr, N_("--protector|-p can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ args->protector = GRUB_PROTECT_TYPE_TPM2;
+ else
+ {
-+ fprintf (stderr, _("'%s' is not a valid protector.\n"), arg);
++ fprintf (stderr, N_("'%s' is not a valid protector.\n"), arg);
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_DEVICE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_DEVICE)
+ {
-+ fprintf (stderr, _("--tpm2-device can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-device can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_PCRS:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS)
+ {
-+ fprintf (stderr, _("--tpm2-pcrs can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-pcrs can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_SRK:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_SRK)
+ {
-+ fprintf (stderr, _("--tpm2-srk can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-srk can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_ASYMMETRIC:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC)
+ {
-+ fprintf (stderr, _("--tpm2-asymmetric can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-asymmetric can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_BANK:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK)
+ {
-+ fprintf (stderr, _("--tpm2-bank can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-bank can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_KEYFILE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE)
+ {
-+ fprintf (stderr, _("--tpm2-keyfile can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-keyfile can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_OUTFILE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE)
+ {
-+ fprintf (stderr, _("--tpm2-outfile can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-outfile can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_EVICT:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT)
+ {
-+ fprintf (stderr, _("--tpm2-evict can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-evict can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+ case GRUB_PROTECT_OPT_TPM2_TPM2KEY:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_TPM2KEY)
+ {
-+ fprintf (stderr, _("--tpm2-tpm2key can only be specified once.\n"));
++ fprintf (stderr, N_("--tpm2-tpm2key can only be specified once.\n"));
+ return EINVAL;
+ }
+
@@ util/grub-protect.c (new)
+}
+
+static grub_err_t
-+grub_protect_args_verify (struct grub_protect_args *args)
++protect_args_verify (struct grub_protect_args *args)
+{
+ if (args->action == GRUB_PROTECT_ACTION_ERROR)
+ {
-+ fprintf (stderr, "--action is mandatory.\n");
++ fprintf (stderr, N_("--action is mandatory.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
@@ util/grub-protect.c (new)
+ * is the only key protector supported by this tool. */
+ if (args->protector != GRUB_PROTECT_TYPE_TPM2)
+ {
-+ fprintf (stderr,
-+ _("--protector is mandatory and only 'tpm2' is currently "
-+ "supported.\n"));
++ fprintf (stderr, N_("--protector is mandatory and only 'tpm2' is currently supported.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ switch (args->protector)
+ {
+ case GRUB_PROTECT_TYPE_TPM2:
-+ return grub_protect_tpm2_args_verify (args);
++ return protect_tpm2_args_verify (args);
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
@@ util/grub-protect.c (new)
+}
+
+static grub_err_t
-+grub_protect_dispatch (struct grub_protect_args *args)
++protect_dispatch (struct grub_protect_args *args)
+{
+ switch (args->protector)
+ {
+ case GRUB_PROTECT_TYPE_TPM2:
-+ return grub_protect_tpm2_run (args);
++ return protect_tpm2_run (args);
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+}
+
+static void
-+grub_protect_init (int *argc, char **argv[])
++protect_init (int *argc, char **argv[])
+{
+ grub_util_host_init (argc, argv);
+
@@ util/grub-protect.c (new)
+}
+
+static void
-+grub_protect_fini (void)
++protect_fini (void)
+{
+ grub_fini_all ();
+ grub_util_biosdisk_fini ();
@@ util/grub-protect.c (new)
+static struct argp grub_protect_argp =
+{
+ .options = grub_protect_options,
-+ .parser = grub_protect_argp_parser,
++ .parser = protect_argp_parser,
+ .args_doc = NULL,
+ .doc =
+ N_("Protect a cleartext key using a GRUB key protector that can retrieve "
@@ util/grub-protect.c (new)
+
+ if (argp_parse (&grub_protect_argp, argc, argv, 0, 0, &args) != 0)
+ {
-+ fprintf (stderr, _("Could not parse arguments.\n"));
++ fprintf (stderr, N_("Could not parse arguments.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
-+ grub_protect_init (&argc, &argv);
++ protect_init (&argc, &argv);
+
-+ err = grub_protect_args_verify (&args);
++ err = protect_args_verify (&args);
+ if (err != GRUB_ERR_NONE)
+ goto exit;
+
-+ err = grub_protect_dispatch (&args);
++ err = protect_dispatch (&args);
+ if (err != GRUB_ERR_NONE)
+ goto exit;
+
+ exit:
-+ grub_protect_fini ();
++ protect_fini ();
+
+ return err;
+}
19: e7191a5d9 < -: --------- tpm2_key_protector: Support authorized policy
20: 8543bec1c < -: --------- tpm2_key_protector: Implement NV index
-: --------- > 25: b5e60d579 tpm2_key_protector: Support authorized policy
-: --------- > 26: 784a1954c tpm2_key_protector: Implement NV index
21: 4fdd0da55 ! 27: bf64c4c21 cryptodisk: Fallback to passphrase
@@ Commit message
cryptodisk: Fallback to passphrase
If a protector is specified, but it fails to unlock the disk, fall back
- to asking for the passphrase. However, an error was set indicating that
- the protector(s) failed. Later code (e.g., LUKS code) fails as
- `grub_errno` is now set. Print the existing errors out first, before
- proceeding with the passphrase.
+ to asking for the passphrase.
+
+ Before requesting the passphrase, the error from the key protector(s)
+ has to be cleared, or the later code (e.g., LUKS code) may stop as
+ 'grub_errno' is set. This commit prints error from the key protector(s)
+ and sets 'grub_errno' to 'GRUB_ERR_NONE' to have a fresh start.
Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
Signed-off-by: Gary Lin <glin@suse.com>
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const char *name,
+ /*
+ * Print the error from key protectors and clear grub_errno.
-+ * Since '--protector' doesn't not coexist with '--password' and
-+ * '--key-file', only "cargs->key_len == 0" is expected if all
-+ * key protectors fail.
++ *
++ * Since '--protector' cannot coexist with '--password' and
++ * '--key-file', in case key protectors fail, only
++ * "cargs->key_len == 0" is expected, so cryptomount falls back
++ * here to request the passphrase.
++ *
++ * To avoid the error from key protectors stops the further code,
++ * print the error to notify the user why key protectors fail and
++ * clear grub_errno to have a fresh start.
+ */
-+ if (grub_errno)
++ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
22: fa2ed9dc6 ! 28: e1d67e568 cryptodisk: wipe out the cached keys from protectors
@@ Commit message
Cc: Fabian Vogt <fvogt@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
## grub-core/disk/cryptodisk.c ##
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs)
23: daa2fe5d6 ! 29: 89452b2c0 diskfilter: look up cryptodisk devices first
@@ grub-core/disk/diskfilter.c: scan_devices (const char *arname)
+ {
+ /* look up the crytodisk devices first */
+ for (p = grub_disk_dev_list; p; p = p->next)
-+ if (p->id == GRUB_DISK_DEVICE_CRYPTODISK_ID
-+ && p->disk_iterate)
++ if (p->id == GRUB_DISK_DEVICE_CRYPTODISK_ID && p->disk_iterate)
+ {
+ if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
+ return;
@@ grub-core/disk/diskfilter.c: scan_devices (const char *arname)
+
+ /* check the devices other than crytodisk */
+ for (p = grub_disk_dev_list; p; p = p->next)
-+ if (p->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
-+ continue;
-+ else if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
-+ && p->disk_iterate)
++ if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID && p->disk_iterate)
+ {
+ if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
+ return;
24: 7622fa1bd ! 30: 37dfe60a8 tpm2_key_protector: Add grub-emu support
@@ grub-core/lib/tss2/tcg2_emu.c (new)
@@
+/*
+ * GRUB -- GRand Unified Bootloader
-+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2024 SUSE LLC
++ * Copyright (C) 2024 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
25: e9847cf50 ! 31: 66969ccc9 tests: Add tpm2_key_protector_test
@@ Commit message
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Glenn Washburn <development@efficientek.com>
Signed-off-by: Gary Lin <glin@suse.com>
+ Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
## Makefile.util.def ##
@@ Makefile.util.def: script = {
-: --------- > 32: 48c991a37 cryptodisk: Document the '-P' option
-: --------- > 33: b9d90b33e docs: Document TPM2 key protector
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* [PATCH v19 01/33] posix_wrap: tweaks in preparation for libtasn1
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
@ 2024-09-06 9:10 ` Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 02/33] libtasn1: import libtasn1-4.19.0 Gary Lin via Grub-devel
` (33 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Daniel Axtens <dja@axtens.net>
- Define SIZEOF_UNSIGNED_LONG_INT, it's the same as
SIZEOF_UNSIGNED_LONG.
- Define WORD_BIT, the size in bits of an int. This is a defined
in the Single Unix Specification and in gnulib's limits.h. gnulib
assumes it's 32 bits on all our platforms, including 64 bit
platforms, so we also use that value.
- Provide strto[u]l[l] preprocessor macros that resolve to
grub_strto[u]l[l]. To avoid gcrypt redefining strtoul, we
also define HAVE_STRTOUL here.
- Implement c-ctype.h and the functions defined in the header.
- Implement strncat in string.h.
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/posix_wrap/c-ctype.h | 114 +++++++++++++++++++++++++++
grub-core/lib/posix_wrap/limits.h | 1 +
grub-core/lib/posix_wrap/stdlib.h | 8 ++
grub-core/lib/posix_wrap/string.h | 21 +++++
grub-core/lib/posix_wrap/sys/types.h | 1 +
5 files changed, 145 insertions(+)
create mode 100644 grub-core/lib/posix_wrap/c-ctype.h
diff --git a/grub-core/lib/posix_wrap/c-ctype.h b/grub-core/lib/posix_wrap/c-ctype.h
new file mode 100644
index 000000000..5f8fc8ce3
--- /dev/null
+++ b/grub-core/lib/posix_wrap/c-ctype.h
@@ -0,0 +1,114 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_POSIX_C_CTYPE_H
+#define GRUB_POSIX_C_CTYPE_H 1
+
+#include <grub/misc.h>
+
+static inline bool
+c_isspace (int c)
+{
+ return !!grub_isspace (c);
+}
+
+static inline bool
+c_isdigit (int c)
+{
+ return !!grub_isdigit (c);
+}
+
+static inline bool
+c_islower (int c)
+{
+ return !!grub_islower (c);
+}
+
+static inline bool
+c_isascii (int c)
+{
+ return !(c & ~0x7f);
+}
+
+static inline bool
+c_isupper (int c)
+{
+ return !!grub_isupper (c);
+}
+
+static inline bool
+c_isxdigit (int c)
+{
+ return !!grub_isxdigit (c);
+}
+
+static inline bool
+c_isprint (int c)
+{
+ return !!grub_isprint (c);
+}
+
+static inline bool
+c_iscntrl (int c)
+{
+ return !grub_isprint (c);
+}
+
+static inline bool
+c_isgraph (int c)
+{
+ return grub_isprint (c) && !grub_isspace (c);
+}
+
+static inline bool
+c_isalnum (int c)
+{
+ return grub_isalpha (c) || grub_isdigit (c);
+}
+
+static inline bool
+c_ispunct (int c)
+{
+ return grub_isprint (c) && !grub_isspace (c) && !c_isalnum (c);
+}
+
+static inline bool
+c_isalpha (int c)
+{
+ return !!grub_isalpha (c);
+}
+
+static inline bool
+c_isblank (int c)
+{
+ return c == ' ' || c == '\t';
+}
+
+static inline int
+c_tolower (int c)
+{
+ return grub_tolower (c);
+}
+
+static inline int
+c_toupper (int c)
+{
+ return grub_toupper (c);
+}
+
+#endif
diff --git a/grub-core/lib/posix_wrap/limits.h b/grub-core/lib/posix_wrap/limits.h
index 26918c8a0..4be7b4080 100644
--- a/grub-core/lib/posix_wrap/limits.h
+++ b/grub-core/lib/posix_wrap/limits.h
@@ -41,5 +41,6 @@
#define LONG_MAX GRUB_LONG_MAX
#define CHAR_BIT 8
+#define WORD_BIT 32
#endif
diff --git a/grub-core/lib/posix_wrap/stdlib.h b/grub-core/lib/posix_wrap/stdlib.h
index f5279756a..14e4efdd0 100644
--- a/grub-core/lib/posix_wrap/stdlib.h
+++ b/grub-core/lib/posix_wrap/stdlib.h
@@ -64,4 +64,12 @@ abort (void)
grub_abort ();
}
+#define strtol grub_strtol
+
+/* for libgcrypt */
+#define HAVE_STRTOUL
+#define strtoul grub_strtoul
+
+#define strtoull grub_strtoull
+
#endif
diff --git a/grub-core/lib/posix_wrap/string.h b/grub-core/lib/posix_wrap/string.h
index 1adb450b5..d3e400d50 100644
--- a/grub-core/lib/posix_wrap/string.h
+++ b/grub-core/lib/posix_wrap/string.h
@@ -84,6 +84,27 @@ memchr (const void *s, int c, grub_size_t n)
return grub_memchr (s, c, n);
}
+static inline char *
+strncat (char *dest, const char *src, grub_size_t n)
+{
+ const char *end;
+ char *str = dest;
+ grub_size_t src_len;
+
+ dest += grub_strlen (dest);
+
+ end = grub_memchr (src, '\0', n);
+ if (end != NULL)
+ src_len = (grub_size_t) (end - src);
+ else
+ src_len = n;
+
+ dest[src_len] = '\0';
+ grub_memcpy (dest, src, src_len);
+
+ return str;
+}
+
#define memcmp grub_memcmp
#define memcpy grub_memcpy
#define memmove grub_memmove
diff --git a/grub-core/lib/posix_wrap/sys/types.h b/grub-core/lib/posix_wrap/sys/types.h
index eeda543c4..2f3e86549 100644
--- a/grub-core/lib/posix_wrap/sys/types.h
+++ b/grub-core/lib/posix_wrap/sys/types.h
@@ -50,6 +50,7 @@ typedef grub_uint8_t byte;
typedef grub_addr_t uintptr_t;
#define SIZEOF_UNSIGNED_LONG GRUB_CPU_SIZEOF_LONG
+#define SIZEOF_UNSIGNED_LONG_INT GRUB_CPU_SIZEOF_LONG
#define SIZEOF_UNSIGNED_INT 4
#define SIZEOF_UNSIGNED_LONG_LONG 8
#define SIZEOF_UNSIGNED_SHORT 2
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 02/33] libtasn1: import libtasn1-4.19.0
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 01/33] posix_wrap: tweaks in preparation for libtasn1 Gary Lin via Grub-devel
@ 2024-09-06 9:10 ` Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 03/33] libtasn1: disable code not needed in grub Gary Lin via Grub-devel
` (32 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Daniel Axtens <dja@axtens.net>
Import a very trimmed-down set of libtasn1 files:
curl -L -O https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.19.0.tar.gz
tar xf libtasn1-4.19.0.tar.gz
rm -rf grub-core/lib/libtasn1/
mkdir -p grub-core/lib/libtasn1/lib/
mkdir -p grub-core/lib/libtasn1/tests/
cp libtasn1-4.19.0/{README.md,COPYING} grub-core/lib/libtasn1/
cp libtasn1-4.19.0/lib/{coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h} grub-core/libtasn1/lib/
cp libtasn1-4.19.0/lib/includes/libtasn1.h grub-core/lib/libtasn1/
cp libtasn1-4.19.0/tests/{CVE-2018-1000654-1_asn1_tab.h,CVE-2018-1000654-2_asn1_tab.h,CVE-2018-1000654.c,object-id-decoding.c,object-id-encoding.c,octet-string.c,reproducers.c,Test_overflow.c,Test_simple.c,Test_strings.c} grub-core/lib/libtasn1/tests
rm -rf libtasn1-4.19.0*
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/libtasn1/COPYING | 16 +
grub-core/lib/libtasn1/README.md | 98 +
grub-core/lib/libtasn1/lib/coding.c | 1425 ++++++++++
grub-core/lib/libtasn1/lib/decoding.c | 2501 +++++++++++++++++
grub-core/lib/libtasn1/lib/element.c | 1109 ++++++++
grub-core/lib/libtasn1/lib/element.h | 42 +
grub-core/lib/libtasn1/lib/errors.c | 100 +
grub-core/lib/libtasn1/lib/gstr.c | 74 +
grub-core/lib/libtasn1/lib/gstr.h | 50 +
grub-core/lib/libtasn1/lib/int.h | 221 ++
grub-core/lib/libtasn1/lib/parser_aux.c | 1178 ++++++++
grub-core/lib/libtasn1/lib/parser_aux.h | 172 ++
grub-core/lib/libtasn1/lib/structure.c | 1225 ++++++++
grub-core/lib/libtasn1/lib/structure.h | 46 +
grub-core/lib/libtasn1/libtasn1.h | 643 +++++
.../tests/CVE-2018-1000654-1_asn1_tab.h | 32 +
.../tests/CVE-2018-1000654-2_asn1_tab.h | 36 +
.../lib/libtasn1/tests/CVE-2018-1000654.c | 72 +
grub-core/lib/libtasn1/tests/Test_overflow.c | 168 ++
grub-core/lib/libtasn1/tests/Test_simple.c | 226 ++
grub-core/lib/libtasn1/tests/Test_strings.c | 156 +
.../lib/libtasn1/tests/object-id-decoding.c | 121 +
.../lib/libtasn1/tests/object-id-encoding.c | 133 +
grub-core/lib/libtasn1/tests/octet-string.c | 230 ++
grub-core/lib/libtasn1/tests/reproducers.c | 90 +
25 files changed, 10164 insertions(+)
create mode 100644 grub-core/lib/libtasn1/COPYING
create mode 100644 grub-core/lib/libtasn1/README.md
create mode 100644 grub-core/lib/libtasn1/lib/coding.c
create mode 100644 grub-core/lib/libtasn1/lib/decoding.c
create mode 100644 grub-core/lib/libtasn1/lib/element.c
create mode 100644 grub-core/lib/libtasn1/lib/element.h
create mode 100644 grub-core/lib/libtasn1/lib/errors.c
create mode 100644 grub-core/lib/libtasn1/lib/gstr.c
create mode 100644 grub-core/lib/libtasn1/lib/gstr.h
create mode 100644 grub-core/lib/libtasn1/lib/int.h
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h
create mode 100644 grub-core/lib/libtasn1/lib/structure.c
create mode 100644 grub-core/lib/libtasn1/lib/structure.h
create mode 100644 grub-core/lib/libtasn1/libtasn1.h
create mode 100644 grub-core/lib/libtasn1/tests/CVE-2018-1000654-1_asn1_tab.h
create mode 100644 grub-core/lib/libtasn1/tests/CVE-2018-1000654-2_asn1_tab.h
create mode 100644 grub-core/lib/libtasn1/tests/CVE-2018-1000654.c
create mode 100644 grub-core/lib/libtasn1/tests/Test_overflow.c
create mode 100644 grub-core/lib/libtasn1/tests/Test_simple.c
create mode 100644 grub-core/lib/libtasn1/tests/Test_strings.c
create mode 100644 grub-core/lib/libtasn1/tests/object-id-decoding.c
create mode 100644 grub-core/lib/libtasn1/tests/object-id-encoding.c
create mode 100644 grub-core/lib/libtasn1/tests/octet-string.c
create mode 100644 grub-core/lib/libtasn1/tests/reproducers.c
diff --git a/grub-core/lib/libtasn1/COPYING b/grub-core/lib/libtasn1/COPYING
new file mode 100644
index 000000000..e8b3628db
--- /dev/null
+++ b/grub-core/lib/libtasn1/COPYING
@@ -0,0 +1,16 @@
+LICENSING
+=========
+
+The libtasn1 library is released under the GNU Lesser General Public
+License (LGPL) version 2.1 or later; see [COPYING.LESSER](doc/COPYING.LESSER)
+for the license terms.
+
+The GNU LGPL applies to the main libtasn1 library, while the
+included applications library are under the GNU GPL version 3.
+The libtasn1 library is located in the lib directory, while the applications
+in src/.
+
+The documentation in doc/ is under the GNU FDL license 1.3.
+
+For any copyright year range specified as YYYY-ZZZZ in this package
+note that the range specifies every single year in that closed interval.
diff --git a/grub-core/lib/libtasn1/README.md b/grub-core/lib/libtasn1/README.md
new file mode 100644
index 000000000..b0305b93e
--- /dev/null
+++ b/grub-core/lib/libtasn1/README.md
@@ -0,0 +1,98 @@
+# Libtasn1 README -- Introduction information
+
+This is GNU Libtasn1, a small ASN.1 library.
+
+The C library (libtasn1.*) is licensed under the GNU Lesser General
+Public License version 2.1 or later. See the file COPYING.LIB.
+
+The command line tool, self tests, examples, and other auxilliary
+files, are licensed under the GNU General Public License version 3.0
+or later. See the file COPYING.
+
+## Building the library
+
+We require several tools to build the software, including:
+
+* [Make](https://www.gnu.org/software/make/)
+* [Automake](https://www.gnu.org/software/automake/) (use 1.11.3 or later)
+* [Autoconf](https://www.gnu.org/software/autoconf/)
+* [Libtool](https://www.gnu.org/software/libtool/)
+* [Texinfo](https://www.gnu.org/software/texinfo/)
+* [help2man](http://www.gnu.org/software/help2man/)
+* [Tar](https://www.gnu.org/software/tar/)
+* [Gzip](https://www.gnu.org/software/gzip/)
+* [bison](https://www.gnu.org/software/bison/)
+* [Texlive & epsf](https://www.tug.org/texlive/) (for PDF manual)
+* [GTK-DOC](https://www.gtk.org/gtk-doc/) (for API manual)
+* [Git](https://git-scm.com/)
+* [libabigail](https://pagure.io/libabigail/) (for abi comparison in make dist)
+* [Valgrind](https://valgrind.org/) (optional)
+
+The required software is typically distributed with your operating
+system, and the instructions for installing them differ. Here are
+some hints:
+
+Debian/Ubuntu:
+```
+sudo apt-get install make git autoconf automake libtool bison
+sudo apt-get install texinfo help2man gtk-doc-tools valgrind abigail-tools
+```
+
+PDF manual - Debian <= stretch:
+```
+sudo apt-get install texlive-generic-recommended texlive texlive-extra-utils
+```
+
+PDF manual - Debian >= buster:
+```
+sudo apt-get install texlive-plain-generic texlive texlive-extra-utils
+```
+
+The next step is to run autoreconf, ./configure, etc:
+
+```
+$ ./bootstrap
+```
+
+Then build the project normally:
+
+```
+$ ./configure
+$ make check
+```
+
+Happy hacking!
+
+
+## Manual
+
+The manual is in the `doc/` directory of the release.
+
+You can also browse the manual online at:
+
+ - https://www.gnu.org/software/libtasn1/manual/
+ - https://gnutls.gitlab.io/libtasn1/manual/
+ - https://gnutls.gitlab.io/libtasn1/manual/libtasn1.html
+ - https://gnutls.gitlab.io/libtasn1/manual/libtasn1.pdf
+ - https://gnutls.gitlab.io/libtasn1/reference/
+ - https://gnutls.gitlab.io/libtasn1/reference/libtasn1.pdf
+
+
+## Code coverage report
+
+The coverage report is at:
+
+ - https://gnutls.gitlab.io/libtasn1/coverage
+
+
+## Issue trackers
+
+ - [Main issue tracker](https://gitlab.com/gnutls/libtasn1/issues)
+ - [oss-fuzz found issues](https://bugs.chromium.org/p/oss-fuzz/issues/list?q=libtasn1&can=2)
+
+
+## Homepage
+
+The project homepage at the gnu site is at:
+
+https://www.gnu.org/software/libtasn1/
diff --git a/grub-core/lib/libtasn1/lib/coding.c b/grub-core/lib/libtasn1/lib/coding.c
new file mode 100644
index 000000000..ea5bc370e
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/coding.c
@@ -0,0 +1,1425 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+/*****************************************************/
+/* File: coding.c */
+/* Description: Functions to create a DER coding of */
+/* an ASN1 type. */
+/*****************************************************/
+
+#include <int.h>
+#include "parser_aux.h"
+#include <gstr.h>
+#include "element.h"
+#include "minmax.h"
+#include <structure.h>
+
+#define MAX_TAG_LEN 16
+
+/******************************************************/
+/* Function : _asn1_error_description_value_not_found */
+/* Description: creates the ErrorDescription string */
+/* for the ASN1_VALUE_NOT_FOUND error. */
+/* Parameters: */
+/* node: node of the tree where the value is NULL. */
+/* ErrorDescription: string returned. */
+/* Return: */
+/******************************************************/
+static void
+_asn1_error_description_value_not_found (asn1_node node,
+ char *ErrorDescription)
+{
+
+ if (ErrorDescription == NULL)
+ return;
+
+ Estrcpy (ErrorDescription, ":: value of element '");
+ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
+ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
+ Estrcat (ErrorDescription, "' not found");
+
+}
+
+/**
+ * asn1_length_der:
+ * @len: value to convert.
+ * @der: buffer to hold the returned encoding (may be %NULL).
+ * @der_len: number of meaningful bytes of ANS (der[0]..der[der_len-1]).
+ *
+ * Creates the DER encoding of the provided length value.
+ * The @der buffer must have enough room for the output. The maximum
+ * length this function will encode is %ASN1_MAX_LENGTH_SIZE.
+ *
+ * To know the size of the DER encoding use a %NULL value for @der.
+ **/
+void
+asn1_length_der (unsigned long int len, unsigned char *der, int *der_len)
+{
+ int k;
+ unsigned char temp[ASN1_MAX_LENGTH_SIZE];
+#if SIZEOF_UNSIGNED_LONG_INT > 8
+ len &= 0xFFFFFFFFFFFFFFFF;
+#endif
+
+ if (len < 128)
+ {
+ /* short form */
+ if (der != NULL)
+ der[0] = (unsigned char) len;
+ *der_len = 1;
+ }
+ else
+ {
+ /* Long form */
+ k = 0;
+ while (len)
+ {
+ temp[k++] = len & 0xFF;
+ len = len >> 8;
+ }
+ *der_len = k + 1;
+ if (der != NULL)
+ {
+ der[0] = ((unsigned char) k & 0x7F) + 128;
+ while (k--)
+ der[*der_len - 1 - k] = temp[k];
+ }
+ }
+}
+
+/******************************************************/
+/* Function : _asn1_tag_der */
+/* Description: creates the DER coding for the CLASS */
+/* and TAG parameters. */
+/* It is limited by the ASN1_MAX_TAG_SIZE variable */
+/* Parameters: */
+/* class: value to convert. */
+/* tag_value: value to convert. */
+/* ans: string returned. */
+/* ans_len: number of meaningful bytes of ANS */
+/* (ans[0]..ans[ans_len-1]). */
+/* Return: */
+/******************************************************/
+static void
+_asn1_tag_der (unsigned char class, unsigned int tag_value,
+ unsigned char ans[ASN1_MAX_TAG_SIZE], int *ans_len)
+{
+ int k;
+ unsigned char temp[ASN1_MAX_TAG_SIZE];
+
+ if (tag_value < 31)
+ {
+ /* short form */
+ ans[0] = (class & 0xE0) + ((unsigned char) (tag_value & 0x1F));
+ *ans_len = 1;
+ }
+ else
+ {
+ /* Long form */
+ ans[0] = (class & 0xE0) + 31;
+ k = 0;
+ while (tag_value != 0)
+ {
+ temp[k++] = tag_value & 0x7F;
+ tag_value >>= 7;
+
+ if (k > ASN1_MAX_TAG_SIZE - 1)
+ break; /* will not encode larger tags */
+ }
+ *ans_len = k + 1;
+ while (k--)
+ ans[*ans_len - 1 - k] = temp[k] + 128;
+ ans[*ans_len - 1] -= 128;
+ }
+}
+
+/**
+ * asn1_octet_der:
+ * @str: the input data.
+ * @str_len: STR length (str[0]..str[*str_len-1]).
+ * @der: encoded string returned.
+ * @der_len: number of meaningful bytes of DER (der[0]..der[der_len-1]).
+ *
+ * Creates a length-value DER encoding for the input data.
+ * The DER encoding of the input data will be placed in the @der variable.
+ *
+ * Note that the OCTET STRING tag is not included in the output.
+ *
+ * This function does not return any value because it is expected
+ * that @der_len will contain enough bytes to store the string
+ * plus the DER encoding. The DER encoding size can be obtained using
+ * asn1_length_der().
+ **/
+void
+asn1_octet_der (const unsigned char *str, int str_len,
+ unsigned char *der, int *der_len)
+{
+ int len_len;
+
+ if (der == NULL || str_len < 0)
+ return;
+
+ asn1_length_der (str_len, der, &len_len);
+ memcpy (der + len_len, str, str_len);
+ *der_len = str_len + len_len;
+}
+
+
+/**
+ * asn1_encode_simple_der:
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
+ * @str: the string data.
+ * @str_len: the string length
+ * @tl: the encoded tag and length
+ * @tl_len: the bytes of the @tl field
+ *
+ * Creates the DER encoding for various simple ASN.1 types like strings etc.
+ * It stores the tag and length in @tl, which should have space for at least
+ * %ASN1_MAX_TL_SIZE bytes. Initially @tl_len should contain the size of @tl.
+ *
+ * The complete DER encoding should consist of the value in @tl appended
+ * with the provided @str.
+ *
+ * Returns: %ASN1_SUCCESS if successful or an error value.
+ **/
+int
+asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
+ unsigned int str_len, unsigned char *tl,
+ unsigned int *tl_len)
+{
+ int tag_len, len_len;
+ unsigned tlen;
+ unsigned char der_tag[ASN1_MAX_TAG_SIZE];
+ unsigned char der_length[ASN1_MAX_LENGTH_SIZE];
+ unsigned char *p;
+
+ if (str == NULL)
+ return ASN1_VALUE_NOT_VALID;
+
+ if (ETYPE_OK (etype) == 0)
+ return ASN1_VALUE_NOT_VALID;
+
+ /* doesn't handle constructed classes */
+ if (ETYPE_CLASS (etype) != ASN1_CLASS_UNIVERSAL)
+ return ASN1_VALUE_NOT_VALID;
+
+ _asn1_tag_der (ETYPE_CLASS (etype), ETYPE_TAG (etype), der_tag, &tag_len);
+
+ asn1_length_der (str_len, der_length, &len_len);
+
+ if (tag_len <= 0 || len_len <= 0)
+ return ASN1_VALUE_NOT_VALID;
+
+ tlen = tag_len + len_len;
+
+ if (*tl_len < tlen)
+ return ASN1_MEM_ERROR;
+
+ p = tl;
+ memcpy (p, der_tag, tag_len);
+ p += tag_len;
+ memcpy (p, der_length, len_len);
+
+ *tl_len = tlen;
+
+ return ASN1_SUCCESS;
+}
+
+/******************************************************/
+/* Function : _asn1_time_der */
+/* Description: creates the DER coding for a TIME */
+/* type (length included). */
+/* Parameters: */
+/* str: TIME null-terminated string. */
+/* der: string returned. */
+/* der_len: number of meaningful bytes of DER */
+/* (der[0]..der[ans_len-1]). Initially it */
+/* if must store the lenght of DER. */
+/* Return: */
+/* ASN1_MEM_ERROR when DER isn't big enough */
+/* ASN1_SUCCESS otherwise */
+/******************************************************/
+static int
+_asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
+ int *der_len)
+{
+ int len_len;
+ int max_len;
+
+ max_len = *der_len;
+
+ asn1_length_der (str_len, (max_len > 0) ? der : NULL, &len_len);
+
+ if ((len_len + str_len) <= max_len)
+ memcpy (der + len_len, str, str_len);
+ *der_len = len_len + str_len;
+
+ if ((*der_len) > max_len)
+ return ASN1_MEM_ERROR;
+
+ return ASN1_SUCCESS;
+}
+
+
+/*
+void
+_asn1_get_utctime_der(unsigned char *der,int *der_len,unsigned char *str)
+{
+ int len_len,str_len;
+ char temp[20];
+
+ if(str==NULL) return;
+ str_len=asn1_get_length_der(der,*der_len,&len_len);
+ if (str_len<0) return;
+ memcpy(temp,der+len_len,str_len);
+ *der_len=str_len+len_len;
+ switch(str_len)
+ {
+ case 11:
+ temp[10]=0;
+ strcat(temp,"00+0000");
+ break;
+ case 13:
+ temp[12]=0;
+ strcat(temp,"+0000");
+ break;
+ case 15:
+ temp[15]=0;
+ memmove(temp+12,temp+10,6);
+ temp[10]=temp[11]='0';
+ break;
+ case 17:
+ temp[17]=0;
+ break;
+ default:
+ return;
+ }
+ strcpy(str,temp);
+}
+*/
+
+static void
+encode_val (uint64_t val, unsigned char *der, int max_len, int *der_len)
+{
+ int first, k;
+ unsigned char bit7;
+
+ first = 0;
+ for (k = sizeof (val); k >= 0; k--)
+ {
+ bit7 = (val >> (k * 7)) & 0x7F;
+ if (bit7 || first || !k)
+ {
+ if (k)
+ bit7 |= 0x80;
+ if (max_len > (*der_len))
+ der[*der_len] = bit7;
+ (*der_len)++;
+ first = 1;
+ }
+ }
+}
+
+/******************************************************/
+/* Function : _asn1_object_id_der */
+/* Description: creates the DER coding for an */
+/* OBJECT IDENTIFIER type (length included). */
+/* Parameters: */
+/* str: OBJECT IDENTIFIER null-terminated string. */
+/* der: string returned. */
+/* der_len: number of meaningful bytes of DER */
+/* (der[0]..der[ans_len-1]). Initially it */
+/* must store the length of DER. */
+/* Return: */
+/* ASN1_MEM_ERROR when DER isn't big enough */
+/* ASN1_SUCCESS if succesful */
+/* or an error value. */
+/******************************************************/
+static int
+_asn1_object_id_der (const char *str, unsigned char *der, int *der_len)
+{
+ int len_len, counter, max_len;
+ char *temp, *n_end, *n_start;
+ uint64_t val, val1 = 0;
+ int str_len = _asn1_strlen (str);
+
+ max_len = *der_len;
+ *der_len = 0;
+
+ if (der == NULL && max_len > 0)
+ return ASN1_VALUE_NOT_VALID;
+
+ temp = malloc (str_len + 2);
+ if (temp == NULL)
+ return ASN1_MEM_ALLOC_ERROR;
+
+ memcpy (temp, str, str_len);
+ temp[str_len] = '.';
+ temp[str_len + 1] = 0;
+
+ counter = 0;
+ n_start = temp;
+ while ((n_end = strchr (n_start, '.')))
+ {
+ *n_end = 0;
+ val = _asn1_strtou64 (n_start, NULL, 10);
+ counter++;
+
+ if (counter == 1)
+ {
+ val1 = val;
+ }
+ else if (counter == 2)
+ {
+ uint64_t val0;
+
+ if (val1 > 2)
+ {
+ free (temp);
+ return ASN1_VALUE_NOT_VALID;
+ }
+ else if ((val1 == 0 || val1 == 1) && val > 39)
+ {
+ free (temp);
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ val0 = 40 * val1 + val;
+ encode_val (val0, der, max_len, der_len);
+ }
+ else
+ {
+ encode_val (val, der, max_len, der_len);
+ }
+ n_start = n_end + 1;
+ }
+
+ asn1_length_der (*der_len, NULL, &len_len);
+ if (max_len >= (*der_len + len_len))
+ {
+ memmove (der + len_len, der, *der_len);
+ asn1_length_der (*der_len, der, &len_len);
+ }
+ *der_len += len_len;
+
+ free (temp);
+
+ if (max_len < (*der_len))
+ return ASN1_MEM_ERROR;
+
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_object_id_der:
+ * @str: An object identifier in numeric, dot format.
+ * @der: buffer to hold the returned encoding (may be %NULL).
+ * @der_len: initially the size of @der; will hold the final size.
+ * @flags: must be zero
+ *
+ * Creates the DER encoding of the provided object identifier.
+ *
+ * Returns: %ASN1_SUCCESS if DER encoding was OK, %ASN1_VALUE_NOT_VALID
+ * if @str is not a valid OID, %ASN1_MEM_ERROR if the @der
+ * vector isn't big enough and in this case @der_len will contain the
+ * length needed.
+ **/
+int
+asn1_object_id_der (const char *str, unsigned char *der, int *der_len,
+ unsigned flags)
+{
+ unsigned char tag_der[MAX_TAG_LEN];
+ int tag_len = 0, r;
+ int max_len = *der_len;
+
+ *der_len = 0;
+
+ _asn1_tag_der (ETYPE_CLASS (ASN1_ETYPE_OBJECT_ID),
+ ETYPE_TAG (ASN1_ETYPE_OBJECT_ID), tag_der, &tag_len);
+
+ if (max_len > tag_len)
+ {
+ memcpy (der, tag_der, tag_len);
+ }
+ max_len -= tag_len;
+ der += tag_len;
+
+ r = _asn1_object_id_der (str, der, &max_len);
+ if (r == ASN1_MEM_ERROR || r == ASN1_SUCCESS)
+ {
+ *der_len = max_len + tag_len;
+ }
+
+ return r;
+}
+
+static const unsigned char bit_mask[] =
+ { 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80 };
+
+/**
+ * asn1_bit_der:
+ * @str: BIT string.
+ * @bit_len: number of meaningful bits in STR.
+ * @der: string returned.
+ * @der_len: number of meaningful bytes of DER
+ * (der[0]..der[ans_len-1]).
+ *
+ * Creates a length-value DER encoding for the input data
+ * as it would have been for a BIT STRING.
+ * The DER encoded data will be copied in @der.
+ *
+ * Note that the BIT STRING tag is not included in the output.
+ *
+ * This function does not return any value because it is expected
+ * that @der_len will contain enough bytes to store the string
+ * plus the DER encoding. The DER encoding size can be obtained using
+ * asn1_length_der().
+ **/
+void
+asn1_bit_der (const unsigned char *str, int bit_len,
+ unsigned char *der, int *der_len)
+{
+ int len_len, len_byte, len_pad;
+
+ if (der == NULL)
+ return;
+
+ len_byte = bit_len >> 3;
+ len_pad = 8 - (bit_len & 7);
+ if (len_pad == 8)
+ len_pad = 0;
+ else
+ len_byte++;
+ asn1_length_der (len_byte + 1, der, &len_len);
+ der[len_len] = len_pad;
+
+ if (str)
+ memcpy (der + len_len + 1, str, len_byte);
+ der[len_len + len_byte] &= bit_mask[len_pad];
+ *der_len = len_byte + len_len + 1;
+}
+
+
+/******************************************************/
+/* Function : _asn1_complete_explicit_tag */
+/* Description: add the length coding to the EXPLICIT */
+/* tags. */
+/* Parameters: */
+/* node: pointer to the tree element. */
+/* der: string with the DER coding of the whole tree*/
+/* counter: number of meaningful bytes of DER */
+/* (der[0]..der[*counter-1]). */
+/* max_len: size of der vector */
+/* Return: */
+/* ASN1_MEM_ERROR if der vector isn't big enough, */
+/* otherwise ASN1_SUCCESS. */
+/******************************************************/
+static int
+_asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
+ int *counter, int *max_len)
+{
+ asn1_node p;
+ int is_tag_implicit, len2, len3;
+ unsigned char temp[SIZEOF_UNSIGNED_INT];
+
+ if (der == NULL && *max_len > 0)
+ return ASN1_VALUE_NOT_VALID;
+
+ is_tag_implicit = 0;
+
+ if (node->type & CONST_TAG)
+ {
+ p = node->down;
+ if (p == NULL)
+ return ASN1_DER_ERROR;
+ /* When there are nested tags we must complete them reverse to
+ the order they were created. This is because completing a tag
+ modifies all data within it, including the incomplete tags
+ which store buffer positions -- simon@josefsson.org 2002-09-06
+ */
+ while (p->right)
+ p = p->right;
+ while (p && p != node->down->left)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_TAG)
+ {
+ if (p->type & CONST_EXPLICIT)
+ {
+ len2 = strtol (p->name, NULL, 10);
+ _asn1_set_name (p, NULL);
+
+ asn1_length_der (*counter - len2, temp, &len3);
+ if (len3 <= (*max_len))
+ {
+ memmove (der + len2 + len3, der + len2,
+ *counter - len2);
+ memcpy (der + len2, temp, len3);
+ }
+ *max_len -= len3;
+ *counter += len3;
+ is_tag_implicit = 0;
+ }
+ else
+ { /* CONST_IMPLICIT */
+ if (!is_tag_implicit)
+ {
+ is_tag_implicit = 1;
+ }
+ }
+ }
+ p = p->left;
+ }
+ }
+
+ if (*max_len < 0)
+ return ASN1_MEM_ERROR;
+
+ return ASN1_SUCCESS;
+}
+
+const tag_and_class_st _asn1_tags[] = {
+ [ASN1_ETYPE_GENERALSTRING] =
+ {ASN1_TAG_GENERALSTRING, ASN1_CLASS_UNIVERSAL, "type:GENERALSTRING"},
+ [ASN1_ETYPE_NUMERIC_STRING] =
+ {ASN1_TAG_NUMERIC_STRING, ASN1_CLASS_UNIVERSAL, "type:NUMERIC_STR"},
+ [ASN1_ETYPE_IA5_STRING] =
+ {ASN1_TAG_IA5_STRING, ASN1_CLASS_UNIVERSAL, "type:IA5_STR"},
+ [ASN1_ETYPE_TELETEX_STRING] =
+ {ASN1_TAG_TELETEX_STRING, ASN1_CLASS_UNIVERSAL, "type:TELETEX_STR"},
+ [ASN1_ETYPE_PRINTABLE_STRING] =
+ {ASN1_TAG_PRINTABLE_STRING, ASN1_CLASS_UNIVERSAL, "type:PRINTABLE_STR"},
+ [ASN1_ETYPE_UNIVERSAL_STRING] =
+ {ASN1_TAG_UNIVERSAL_STRING, ASN1_CLASS_UNIVERSAL, "type:UNIVERSAL_STR"},
+ [ASN1_ETYPE_BMP_STRING] =
+ {ASN1_TAG_BMP_STRING, ASN1_CLASS_UNIVERSAL, "type:BMP_STR"},
+ [ASN1_ETYPE_UTF8_STRING] =
+ {ASN1_TAG_UTF8_STRING, ASN1_CLASS_UNIVERSAL, "type:UTF8_STR"},
+ [ASN1_ETYPE_VISIBLE_STRING] =
+ {ASN1_TAG_VISIBLE_STRING, ASN1_CLASS_UNIVERSAL, "type:VISIBLE_STR"},
+ [ASN1_ETYPE_OCTET_STRING] =
+ {ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, "type:OCT_STR"},
+ [ASN1_ETYPE_BIT_STRING] =
+ {ASN1_TAG_BIT_STRING, ASN1_CLASS_UNIVERSAL, "type:BIT_STR"},
+ [ASN1_ETYPE_OBJECT_ID] =
+ {ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, "type:OBJ_ID"},
+ [ASN1_ETYPE_NULL] = {ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL, "type:NULL"},
+ [ASN1_ETYPE_BOOLEAN] =
+ {ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, "type:BOOLEAN"},
+ [ASN1_ETYPE_INTEGER] =
+ {ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, "type:INTEGER"},
+ [ASN1_ETYPE_ENUMERATED] =
+ {ASN1_TAG_ENUMERATED, ASN1_CLASS_UNIVERSAL, "type:ENUMERATED"},
+ [ASN1_ETYPE_SEQUENCE] =
+ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
+ "type:SEQUENCE"},
+ [ASN1_ETYPE_SEQUENCE_OF] =
+ {ASN1_TAG_SEQUENCE, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
+ "type:SEQ_OF"},
+ [ASN1_ETYPE_SET] =
+ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED, "type:SET"},
+ [ASN1_ETYPE_SET_OF] =
+ {ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED,
+ "type:SET_OF"},
+ [ASN1_ETYPE_GENERALIZED_TIME] =
+ {ASN1_TAG_GENERALIZEDTime, ASN1_CLASS_UNIVERSAL, "type:GENERALIZED_TIME"},
+ [ASN1_ETYPE_UTC_TIME] =
+ {ASN1_TAG_UTCTime, ASN1_CLASS_UNIVERSAL, "type:UTC_TIME"},
+};
+
+unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
+
+/******************************************************/
+/* Function : _asn1_insert_tag_der */
+/* Description: creates the DER coding of tags of one */
+/* NODE. */
+/* Parameters: */
+/* node: pointer to the tree element. */
+/* der: string returned */
+/* counter: number of meaningful bytes of DER */
+/* (counter[0]..der[*counter-1]). */
+/* max_len: size of der vector */
+/* Return: */
+/* ASN1_GENERIC_ERROR if the type is unknown, */
+/* ASN1_MEM_ERROR if der vector isn't big enough, */
+/* otherwise ASN1_SUCCESS. */
+/******************************************************/
+static int
+_asn1_insert_tag_der (asn1_node node, unsigned char *der, int *counter,
+ int *max_len)
+{
+ asn1_node p;
+ int tag_len, is_tag_implicit;
+ unsigned char class, class_implicit =
+ 0, temp[MAX (SIZEOF_UNSIGNED_INT * 3 + 1, LTOSTR_MAX_SIZE)];
+ unsigned long tag_implicit = 0;
+ unsigned char tag_der[MAX_TAG_LEN];
+
+ is_tag_implicit = 0;
+
+ if (node->type & CONST_TAG)
+ {
+ p = node->down;
+ while (p)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_TAG)
+ {
+ if (p->type & CONST_APPLICATION)
+ class = ASN1_CLASS_APPLICATION;
+ else if (p->type & CONST_UNIVERSAL)
+ class = ASN1_CLASS_UNIVERSAL;
+ else if (p->type & CONST_PRIVATE)
+ class = ASN1_CLASS_PRIVATE;
+ else
+ class = ASN1_CLASS_CONTEXT_SPECIFIC;
+
+ if (p->type & CONST_EXPLICIT)
+ {
+ if (is_tag_implicit)
+ _asn1_tag_der (class_implicit, tag_implicit, tag_der,
+ &tag_len);
+ else
+ _asn1_tag_der (class | ASN1_CLASS_STRUCTURED,
+ _asn1_strtoul (p->value, NULL, 10),
+ tag_der, &tag_len);
+
+ *max_len -= tag_len;
+ if (der && *max_len >= 0)
+ memcpy (der + *counter, tag_der, tag_len);
+ *counter += tag_len;
+
+ _asn1_ltostr (*counter, (char *) temp);
+ _asn1_set_name (p, (const char *) temp);
+
+ is_tag_implicit = 0;
+ }
+ else
+ { /* CONST_IMPLICIT */
+ if (!is_tag_implicit)
+ {
+ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
+ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
+ || (type_field (node->type) == ASN1_ETYPE_SET)
+ || (type_field (node->type) == ASN1_ETYPE_SET_OF))
+ class |= ASN1_CLASS_STRUCTURED;
+ class_implicit = class;
+ tag_implicit = _asn1_strtoul (p->value, NULL, 10);
+ is_tag_implicit = 1;
+ }
+ }
+ }
+ p = p->right;
+ }
+ }
+
+ if (is_tag_implicit)
+ {
+ _asn1_tag_der (class_implicit, tag_implicit, tag_der, &tag_len);
+ }
+ else
+ {
+ unsigned type = type_field (node->type);
+ switch (type)
+ {
+ CASE_HANDLED_ETYPES:
+ _asn1_tag_der (_asn1_tags[type].class, _asn1_tags[type].tag,
+ tag_der, &tag_len);
+ break;
+ case ASN1_ETYPE_TAG:
+ case ASN1_ETYPE_CHOICE:
+ case ASN1_ETYPE_ANY:
+ tag_len = 0;
+ break;
+ default:
+ return ASN1_GENERIC_ERROR;
+ }
+ }
+
+ *max_len -= tag_len;
+ if (der && *max_len >= 0)
+ memcpy (der + *counter, tag_der, tag_len);
+ *counter += tag_len;
+
+ if (*max_len < 0)
+ return ASN1_MEM_ERROR;
+
+ return ASN1_SUCCESS;
+}
+
+/******************************************************/
+/* Function : _asn1_ordering_set */
+/* Description: puts the elements of a SET type in */
+/* the correct order according to DER rules. */
+/* Parameters: */
+/* der: string with the DER coding. */
+/* node: pointer to the SET element. */
+/* Return: */
+/* ASN1_SUCCESS if successful */
+/* or an error value. */
+/******************************************************/
+static int
+_asn1_ordering_set (unsigned char *der, int der_len, asn1_node node)
+{
+ struct vet
+ {
+ int end;
+ unsigned long value;
+ struct vet *next, *prev;
+ };
+
+ int counter, len, len2;
+ struct vet *first, *last, *p_vet, *p2_vet;
+ asn1_node p;
+ unsigned char class, *temp;
+ unsigned long tag, t;
+ int err;
+
+ counter = 0;
+
+ if (type_field (node->type) != ASN1_ETYPE_SET)
+ return ASN1_VALUE_NOT_VALID;
+
+ p = node->down;
+ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
+ (type_field (p->type) == ASN1_ETYPE_SIZE)))
+ p = p->right;
+
+ if ((p == NULL) || (p->right == NULL))
+ return ASN1_SUCCESS;
+
+ first = last = NULL;
+ while (p)
+ {
+ p_vet = malloc (sizeof (struct vet));
+ if (p_vet == NULL)
+ {
+ err = ASN1_MEM_ALLOC_ERROR;
+ goto error;
+ }
+
+ p_vet->next = NULL;
+ p_vet->prev = last;
+ if (first == NULL)
+ first = p_vet;
+ else
+ last->next = p_vet;
+ last = p_vet;
+
+ /* tag value calculation */
+ err = asn1_get_tag_der (der + counter, der_len - counter, &class, &len2,
+ &tag);
+ if (err != ASN1_SUCCESS)
+ goto error;
+
+ t = ((unsigned int) class) << 24;
+ p_vet->value = t | tag;
+ counter += len2;
+
+ /* extraction and length */
+ len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
+ if (len2 < 0)
+ {
+ err = ASN1_DER_ERROR;
+ goto error;
+ }
+ counter += len + len2;
+
+ p_vet->end = counter;
+ p = p->right;
+ }
+
+ p_vet = first;
+
+ while (p_vet)
+ {
+ p2_vet = p_vet->next;
+ counter = 0;
+ while (p2_vet)
+ {
+ if (p_vet->value > p2_vet->value)
+ {
+ /* change position */
+ temp = malloc (p_vet->end - counter);
+ if (temp == NULL)
+ {
+ err = ASN1_MEM_ALLOC_ERROR;
+ goto error;
+ }
+
+ memcpy (temp, der + counter, p_vet->end - counter);
+ memcpy (der + counter, der + p_vet->end,
+ p2_vet->end - p_vet->end);
+ memcpy (der + counter + p2_vet->end - p_vet->end, temp,
+ p_vet->end - counter);
+ free (temp);
+
+ tag = p_vet->value;
+ p_vet->value = p2_vet->value;
+ p2_vet->value = tag;
+
+ p_vet->end = counter + (p2_vet->end - p_vet->end);
+ }
+ counter = p_vet->end;
+
+ p2_vet = p2_vet->next;
+ p_vet = p_vet->next;
+ }
+
+ if (p_vet != first)
+ p_vet->prev->next = NULL;
+ else
+ first = NULL;
+ free (p_vet);
+ p_vet = first;
+ }
+ return ASN1_SUCCESS;
+
+error:
+ while (first != NULL)
+ {
+ p_vet = first;
+ first = first->next;
+ free (p_vet);
+ }
+ return err;
+}
+
+struct vet
+{
+ unsigned char *ptr;
+ int size;
+};
+
+static int
+setof_compar (const void *_e1, const void *_e2)
+{
+ unsigned length;
+ const struct vet *e1 = _e1, *e2 = _e2;
+ int rval;
+
+ /* The encodings of the component values of a set-of value shall
+ * appear in ascending order, the encodings being compared
+ * as octet strings with the shorter components being
+ * padded at their trailing end with 0-octets.
+ * The padding octets are for comparison purposes and
+ * do not appear in the encodings.
+ */
+ length = MIN (e1->size, e2->size);
+
+ rval = memcmp (e1->ptr, e2->ptr, length);
+ if (rval == 0 && e1->size != e2->size)
+ {
+ if (e1->size > e2->size)
+ rval = 1;
+ else if (e2->size > e1->size)
+ rval = -1;
+ }
+
+ return rval;
+}
+
+/******************************************************/
+/* Function : _asn1_ordering_set_of */
+/* Description: puts the elements of a SET OF type in */
+/* the correct order according to DER rules. */
+/* Parameters: */
+/* der: string with the DER coding. */
+/* node: pointer to the SET OF element. */
+/* Return: */
+/* ASN1_SUCCESS if successful */
+/* or an error value. */
+/******************************************************/
+static int
+_asn1_ordering_set_of (unsigned char *der, int der_len, asn1_node node)
+{
+ int counter, len, len2;
+ struct vet *list = NULL, *tlist;
+ unsigned list_size = 0;
+ struct vet *p_vet;
+ asn1_node p;
+ unsigned char class;
+ unsigned i;
+ unsigned char *out = NULL;
+ int err;
+
+ counter = 0;
+
+ if (type_field (node->type) != ASN1_ETYPE_SET_OF)
+ return ASN1_VALUE_NOT_VALID;
+
+ p = node->down;
+ while (p && ((type_field (p->type) == ASN1_ETYPE_TAG) ||
+ (type_field (p->type) == ASN1_ETYPE_SIZE)))
+ p = p->right;
+ if (p == NULL)
+ return ASN1_VALUE_NOT_VALID;
+ p = p->right;
+
+ if ((p == NULL) || (p->right == NULL))
+ return ASN1_SUCCESS;
+
+ while (p)
+ {
+ list_size++;
+ tlist = realloc (list, list_size * sizeof (struct vet));
+ if (tlist == NULL)
+ {
+ err = ASN1_MEM_ALLOC_ERROR;
+ goto error;
+ }
+ list = tlist;
+ p_vet = &list[list_size - 1];
+
+ p_vet->ptr = der + counter;
+ p_vet->size = 0;
+
+ /* extraction of tag and length */
+ if (der_len - counter > 0)
+ {
+ err = asn1_get_tag_der (der + counter, der_len - counter, &class,
+ &len, NULL);
+ if (err != ASN1_SUCCESS)
+ goto error;
+ counter += len;
+ p_vet->size += len;
+
+ len2 = asn1_get_length_der (der + counter, der_len - counter, &len);
+ if (len2 < 0)
+ {
+ err = ASN1_DER_ERROR;
+ goto error;
+ }
+ counter += len + len2;
+ p_vet->size += len + len2;
+
+ }
+ else
+ {
+ err = ASN1_DER_ERROR;
+ goto error;
+ }
+ p = p->right;
+ }
+
+ if (counter > der_len)
+ {
+ err = ASN1_DER_ERROR;
+ goto error;
+ }
+
+ qsort (list, list_size, sizeof (struct vet), setof_compar);
+
+ out = malloc (der_len);
+ if (out == NULL)
+ {
+ err = ASN1_MEM_ERROR;
+ goto error;
+ }
+
+ /* the sum of p_vet->size == der_len */
+ counter = 0;
+ for (i = 0; i < list_size; i++)
+ {
+ p_vet = &list[i];
+ memcpy (out + counter, p_vet->ptr, p_vet->size);
+ counter += p_vet->size;
+ }
+ memcpy (der, out, der_len);
+ free (out);
+
+ err = ASN1_SUCCESS;
+
+error:
+ free (list);
+ return err;
+}
+
+/**
+ * asn1_der_coding:
+ * @element: pointer to an ASN1 element
+ * @name: the name of the structure you want to encode (it must be
+ * inside *POINTER).
+ * @ider: vector that will contain the DER encoding. DER must be a
+ * pointer to memory cells already allocated.
+ * @len: number of bytes of *@ider: @ider[0]..@ider[len-1], Initialy
+ * holds the sizeof of der vector.
+ * @ErrorDescription: return the error description or an empty
+ * string if success.
+ *
+ * Creates the DER encoding for the NAME structure (inside *POINTER
+ * structure).
+ *
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
+ * if @name is not a valid element, %ASN1_VALUE_NOT_FOUND if there
+ * is an element without a value, %ASN1_MEM_ERROR if the @ider
+ * vector isn't big enough and in this case @len will contain the
+ * length needed.
+ **/
+int
+asn1_der_coding (asn1_node_const element, const char *name, void *ider,
+ int *len, char *ErrorDescription)
+{
+ asn1_node node, p, p2;
+ unsigned char temp[MAX (LTOSTR_MAX_SIZE, SIZEOF_UNSIGNED_LONG_INT * 3 + 1)];
+ int counter, counter_old, len2, len3, move, max_len, max_len_old;
+ int err;
+ unsigned char *der = ider;
+ unsigned char dummy;
+
+ if (ErrorDescription)
+ ErrorDescription[0] = 0;
+
+ node = asn1_find_node (element, name);
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ /* Node is now a locally allocated variable.
+ * That is because in some point we modify the
+ * structure, and I don't know why! --nmav
+ */
+ node = _asn1_copy_structure3 (node);
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ max_len = *len;
+
+ if (der == NULL && max_len > 0)
+ {
+ err = ASN1_VALUE_NOT_VALID;
+ goto error;
+ }
+
+ counter = 0;
+ move = DOWN;
+ p = node;
+
+ while (1)
+ {
+
+ counter_old = counter;
+ max_len_old = max_len;
+ if (move != UP)
+ {
+ p->start = counter;
+ err = _asn1_insert_tag_der (p, der, &counter, &max_len);
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
+ goto error;
+ }
+ switch (type_field (p->type))
+ {
+ case ASN1_ETYPE_NULL:
+ max_len--;
+ if (der != NULL && max_len >= 0)
+ der[counter] = 0;
+ counter++;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_BOOLEAN:
+ if ((p->type & CONST_DEFAULT) && (p->value == NULL))
+ {
+ counter = counter_old;
+ max_len = max_len_old;
+ }
+ else
+ {
+ if (p->value == NULL)
+ {
+ _asn1_error_description_value_not_found (p,
+ ErrorDescription);
+ err = ASN1_VALUE_NOT_FOUND;
+ goto error;
+ }
+ max_len -= 2;
+ if (der != NULL && max_len >= 0)
+ {
+ der[counter++] = 1;
+ if (p->value[0] == 'F')
+ der[counter++] = 0;
+ else
+ der[counter++] = 0xFF;
+ }
+ else
+ counter += 2;
+ }
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_INTEGER:
+ case ASN1_ETYPE_ENUMERATED:
+ if ((p->type & CONST_DEFAULT) && (p->value == NULL))
+ {
+ counter = counter_old;
+ max_len = max_len_old;
+ }
+ else
+ {
+ if (p->value == NULL)
+ {
+ _asn1_error_description_value_not_found (p,
+ ErrorDescription);
+ err = ASN1_VALUE_NOT_FOUND;
+ goto error;
+ }
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3);
+ if (len2 < 0)
+ {
+ err = ASN1_DER_ERROR;
+ goto error;
+ }
+ max_len -= len2 + len3;
+ if (der != NULL && max_len >= 0)
+ memcpy (der + counter, p->value, len3 + len2);
+ counter += len3 + len2;
+ }
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_OBJECT_ID:
+ if ((p->type & CONST_DEFAULT) && (p->value == NULL))
+ {
+ counter = counter_old;
+ max_len = max_len_old;
+ }
+ else
+ {
+ if (p->value == NULL)
+ {
+ _asn1_error_description_value_not_found (p,
+ ErrorDescription);
+ err = ASN1_VALUE_NOT_FOUND;
+ goto error;
+ }
+ len2 = max_len;
+ err =
+ _asn1_object_id_der ((char *) p->value,
+ der ? der + counter : &dummy, &len2);
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
+ goto error;
+
+ max_len -= len2;
+ counter += len2;
+ }
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_GENERALIZED_TIME:
+ case ASN1_ETYPE_UTC_TIME:
+ if (p->value == NULL)
+ {
+ _asn1_error_description_value_not_found (p, ErrorDescription);
+ err = ASN1_VALUE_NOT_FOUND;
+ goto error;
+ }
+ len2 = max_len;
+ err =
+ _asn1_time_der (p->value, p->value_len,
+ der ? der + counter : &dummy, &len2);
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
+ goto error;
+
+ max_len -= len2;
+ counter += len2;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_OCTET_STRING:
+ case ASN1_ETYPE_GENERALSTRING:
+ case ASN1_ETYPE_NUMERIC_STRING:
+ case ASN1_ETYPE_IA5_STRING:
+ case ASN1_ETYPE_TELETEX_STRING:
+ case ASN1_ETYPE_PRINTABLE_STRING:
+ case ASN1_ETYPE_UNIVERSAL_STRING:
+ case ASN1_ETYPE_BMP_STRING:
+ case ASN1_ETYPE_UTF8_STRING:
+ case ASN1_ETYPE_VISIBLE_STRING:
+ case ASN1_ETYPE_BIT_STRING:
+ if (p->value == NULL)
+ {
+ _asn1_error_description_value_not_found (p, ErrorDescription);
+ err = ASN1_VALUE_NOT_FOUND;
+ goto error;
+ }
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3);
+ if (len2 < 0)
+ {
+ err = ASN1_DER_ERROR;
+ goto error;
+ }
+ max_len -= len2 + len3;
+ if (der != NULL && max_len >= 0)
+ memcpy (der + counter, p->value, len3 + len2);
+ counter += len3 + len2;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_SEQUENCE:
+ case ASN1_ETYPE_SET:
+ if (move != UP)
+ {
+ p->tmp_ival = counter;
+ if (p->down == NULL)
+ {
+ move = UP;
+ continue;
+ }
+ else
+ {
+ p2 = p->down;
+ while (p2 && (type_field (p2->type) == ASN1_ETYPE_TAG))
+ p2 = p2->right;
+ if (p2)
+ {
+ p = p2;
+ move = RIGHT;
+ continue;
+ }
+ move = UP;
+ continue;
+ }
+ }
+ else
+ { /* move==UP */
+ len2 = p->tmp_ival;
+ p->tmp_ival = 0;
+ if ((type_field (p->type) == ASN1_ETYPE_SET) && (max_len >= 0))
+ {
+ err =
+ _asn1_ordering_set (der ? der + len2 : &dummy,
+ counter - len2, p);
+ if (err != ASN1_SUCCESS)
+ goto error;
+ }
+ asn1_length_der (counter - len2, temp, &len3);
+ max_len -= len3;
+ if (der != NULL && max_len >= 0)
+ {
+ memmove (der + len2 + len3, der + len2, counter - len2);
+ memcpy (der + len2, temp, len3);
+ }
+ counter += len3;
+ move = RIGHT;
+ }
+ break;
+ case ASN1_ETYPE_SEQUENCE_OF:
+ case ASN1_ETYPE_SET_OF:
+ if (move != UP)
+ {
+ p->tmp_ival = counter;
+ p = p->down;
+ while ((type_field (p->type) == ASN1_ETYPE_TAG)
+ || (type_field (p->type) == ASN1_ETYPE_SIZE))
+ p = p->right;
+ if (p->right)
+ {
+ p = p->right;
+ move = RIGHT;
+ continue;
+ }
+ else
+ p = _asn1_find_up (p);
+ move = UP;
+ }
+ if (move == UP)
+ {
+ len2 = p->tmp_ival;
+ p->tmp_ival = 0;
+ if ((type_field (p->type) == ASN1_ETYPE_SET_OF)
+ && (counter - len2 > 0) && (max_len >= 0))
+ {
+ err =
+ _asn1_ordering_set_of (der ? der + len2 : &dummy,
+ counter - len2, p);
+ if (err != ASN1_SUCCESS)
+ goto error;
+ }
+ asn1_length_der (counter - len2, temp, &len3);
+ max_len -= len3;
+ if (der != NULL && max_len >= 0)
+ {
+ memmove (der + len2 + len3, der + len2, counter - len2);
+ memcpy (der + len2, temp, len3);
+ }
+ counter += len3;
+ move = RIGHT;
+ }
+ break;
+ case ASN1_ETYPE_ANY:
+ if (p->value == NULL)
+ {
+ _asn1_error_description_value_not_found (p, ErrorDescription);
+ err = ASN1_VALUE_NOT_FOUND;
+ goto error;
+ }
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3);
+ if (len2 < 0)
+ {
+ err = ASN1_DER_ERROR;
+ goto error;
+ }
+ max_len -= len2;
+ if (der != NULL && max_len >= 0)
+ memcpy (der + counter, p->value + len3, len2);
+ counter += len2;
+ move = RIGHT;
+ break;
+ default:
+ move = (move == UP) ? RIGHT : DOWN;
+ break;
+ }
+
+ if ((move != DOWN) && (counter != counter_old))
+ {
+ p->end = counter - 1;
+ err = _asn1_complete_explicit_tag (p, der, &counter, &max_len);
+ if (err != ASN1_SUCCESS && err != ASN1_MEM_ERROR)
+ goto error;
+ }
+
+ if (p == node && move != DOWN)
+ break;
+
+ if (move == DOWN)
+ {
+ if (p->down)
+ p = p->down;
+ else
+ move = RIGHT;
+ }
+ if (move == RIGHT)
+ {
+ if (p->right)
+ p = p->right;
+ else
+ move = UP;
+ }
+ if (move == UP)
+ p = _asn1_find_up (p);
+ }
+
+ *len = counter;
+
+ if (max_len < 0)
+ {
+ err = ASN1_MEM_ERROR;
+ goto error;
+ }
+
+ err = ASN1_SUCCESS;
+
+error:
+ asn1_delete_structure (&node);
+ return err;
+}
diff --git a/grub-core/lib/libtasn1/lib/decoding.c b/grub-core/lib/libtasn1/lib/decoding.c
new file mode 100644
index 000000000..b9245c486
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/decoding.c
@@ -0,0 +1,2501 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+/*****************************************************/
+/* File: decoding.c */
+/* Description: Functions to manage DER decoding */
+/*****************************************************/
+
+#include <int.h>
+#include <parser_aux.h>
+#include <gstr.h>
+#include <structure.h>
+#include <element.h>
+#include <limits.h>
+#include <intprops.h>
+#include "c-ctype.h"
+
+#ifdef DEBUG
+# define warn() fprintf(stderr, "%s: %d\n", __func__, __LINE__)
+#else
+# define warn()
+#endif
+
+#define IS_ERR(len, flags) (len < -1 || ((flags & ASN1_DECODE_FLAG_STRICT_DER) && len < 0))
+
+#define HAVE_TWO(x) (x>=2?1:0)
+
+/* Decoding flags (dflags) used in several decoding functions.
+ * DECODE_FLAG_HAVE_TAG: The provided buffer includes a tag
+ * DECODE_FLAG_CONSTRUCTED: The provided buffer is of indefinite encoding (useful
+ * when no tags are present).
+ * DECODE_FLAG_LEVEL1: Internal flag to indicate a level of recursion for BER strings.
+ * DECODE_FLAG_LEVEL2: Internal flag to indicate two levels of recursion for BER strings.
+ * DECODE_FLAG_LEVEL3: Internal flag to indicate three levels of recursion for BER strings.
+ * This is the maximum levels of recursion possible to prevent stack
+ * exhaustion.
+ */
+
+#define DECODE_FLAG_HAVE_TAG 1
+#define DECODE_FLAG_CONSTRUCTED (1<<1)
+#define DECODE_FLAG_LEVEL1 (1<<2)
+#define DECODE_FLAG_LEVEL2 (1<<3)
+#define DECODE_FLAG_LEVEL3 (1<<4)
+
+#define DECR_LEN(l, s) do { \
+ l -= s; \
+ if (l < 0) { \
+ warn(); \
+ result = ASN1_DER_ERROR; \
+ goto cleanup; \
+ } \
+ } while (0)
+
+static int
+_asn1_get_indefinite_length_string (const unsigned char *der, int der_len,
+ int *len);
+
+static int
+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len, unsigned char **str,
+ unsigned int *str_len, unsigned int *ber_len,
+ unsigned dflags);
+
+static int
+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len, const unsigned char **str,
+ unsigned int *str_len, unsigned dflags);
+
+static void
+_asn1_error_description_tag_error (asn1_node node, char *ErrorDescription)
+{
+
+ Estrcpy (ErrorDescription, ":: tag error near element '");
+ _asn1_hierarchical_name (node, ErrorDescription + strlen (ErrorDescription),
+ ASN1_MAX_ERROR_DESCRIPTION_SIZE - 40);
+ Estrcat (ErrorDescription, "'");
+
+}
+
+/**
+ * asn1_get_length_der:
+ * @der: DER data to decode.
+ * @der_len: Length of DER data to decode.
+ * @len: Output variable containing the length of the DER length field.
+ *
+ * Extract a length field from DER data.
+ *
+ * Returns: Return the decoded length value, or -1 on indefinite
+ * length, or -2 when the value was too big to fit in a int, or -4
+ * when the decoded length value plus @len would exceed @der_len.
+ **/
+long
+asn1_get_length_der (const unsigned char *der, int der_len, int *len)
+{
+ unsigned int ans;
+ int k, punt, sum;
+
+ *len = 0;
+ if (der_len <= 0)
+ return 0;
+
+ if (!(der[0] & 128))
+ {
+ /* short form */
+ *len = 1;
+ ans = der[0];
+ }
+ else
+ {
+ /* Long form */
+ k = der[0] & 0x7F;
+ punt = 1;
+ if (k)
+ { /* definite length method */
+ ans = 0;
+ while (punt <= k && punt < der_len)
+ {
+ if (INT_MULTIPLY_OVERFLOW (ans, 256))
+ return -2;
+ ans *= 256;
+
+ if (INT_ADD_OVERFLOW (ans, ((unsigned) der[punt])))
+ return -2;
+ ans += der[punt];
+ punt++;
+ }
+ }
+ else
+ { /* indefinite length method */
+ *len = punt;
+ return -1;
+ }
+
+ *len = punt;
+ }
+
+ sum = ans;
+ if (ans >= INT_MAX || INT_ADD_OVERFLOW (sum, (*len)))
+ return -2;
+ sum += *len;
+
+ if (sum > der_len)
+ return -4;
+
+ return ans;
+}
+
+/**
+ * asn1_get_tag_der:
+ * @der: DER data to decode.
+ * @der_len: Length of DER data to decode.
+ * @cls: Output variable containing decoded class.
+ * @len: Output variable containing the length of the DER TAG data.
+ * @tag: Output variable containing the decoded tag (may be %NULL).
+ *
+ * Decode the class and TAG from DER code.
+ *
+ * Returns: Returns %ASN1_SUCCESS on success, or an error.
+ **/
+int
+asn1_get_tag_der (const unsigned char *der, int der_len,
+ unsigned char *cls, int *len, unsigned long *tag)
+{
+ unsigned int ris;
+ int punt;
+
+ if (der == NULL || der_len < 2 || len == NULL)
+ return ASN1_DER_ERROR;
+
+ *cls = der[0] & 0xE0;
+ if ((der[0] & 0x1F) != 0x1F)
+ {
+ /* short form */
+ *len = 1;
+ ris = der[0] & 0x1F;
+ }
+ else
+ {
+ /* Long form */
+ punt = 1;
+ ris = 0;
+ while (punt < der_len && der[punt] & 128)
+ {
+
+ if (INT_MULTIPLY_OVERFLOW (ris, 128))
+ return ASN1_DER_ERROR;
+ ris *= 128;
+
+ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
+ return ASN1_DER_ERROR;
+ ris += (der[punt] & 0x7F);
+ punt++;
+ }
+
+ if (punt >= der_len)
+ return ASN1_DER_ERROR;
+
+ if (INT_MULTIPLY_OVERFLOW (ris, 128))
+ return ASN1_DER_ERROR;
+ ris *= 128;
+
+ if (INT_ADD_OVERFLOW (ris, ((unsigned) (der[punt] & 0x7F))))
+ return ASN1_DER_ERROR;
+ ris += (der[punt] & 0x7F);
+ punt++;
+
+ *len = punt;
+ }
+
+ if (tag)
+ *tag = ris;
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_get_length_ber:
+ * @ber: BER data to decode.
+ * @ber_len: Length of BER data to decode.
+ * @len: Output variable containing the length of the BER length field.
+ *
+ * Extract a length field from BER data. The difference to
+ * asn1_get_length_der() is that this function will return a length
+ * even if the value has indefinite encoding.
+ *
+ * Returns: Return the decoded length value, or negative value when
+ * the value was too big.
+ *
+ * Since: 2.0
+ **/
+long
+asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len)
+{
+ int ret;
+ long err;
+
+ ret = asn1_get_length_der (ber, ber_len, len);
+
+ if (ret == -1 && ber_len > 1)
+ { /* indefinite length method */
+ err = _asn1_get_indefinite_length_string (ber + 1, ber_len - 1, &ret);
+ if (err != ASN1_SUCCESS)
+ return -3;
+ }
+
+ return ret;
+}
+
+/**
+ * asn1_get_octet_der:
+ * @der: DER data to decode containing the OCTET SEQUENCE.
+ * @der_len: The length of the @der data to decode.
+ * @ret_len: Output variable containing the encoded length of the DER data.
+ * @str: Pre-allocated output buffer to put decoded OCTET SEQUENCE in.
+ * @str_size: Length of pre-allocated output buffer.
+ * @str_len: Output variable containing the length of the contents of the OCTET SEQUENCE.
+ *
+ * Extract an OCTET SEQUENCE from DER data. Note that this function
+ * expects the DER data past the tag field, i.e., the length and
+ * content octets.
+ *
+ * Returns: Returns %ASN1_SUCCESS on success, or an error.
+ **/
+int
+asn1_get_octet_der (const unsigned char *der, int der_len,
+ int *ret_len, unsigned char *str, int str_size,
+ int *str_len)
+{
+ int len_len = 0;
+
+ if (der_len <= 0)
+ return ASN1_GENERIC_ERROR;
+
+ *str_len = asn1_get_length_der (der, der_len, &len_len);
+
+ if (*str_len < 0)
+ return ASN1_DER_ERROR;
+
+ *ret_len = *str_len + len_len;
+ if (str_size >= *str_len)
+ {
+ if (*str_len > 0 && str != NULL)
+ memcpy (str, der + len_len, *str_len);
+ }
+ else
+ {
+ return ASN1_MEM_ERROR;
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+/*-
+ * _asn1_get_time_der:
+ * @type: %ASN1_ETYPE_GENERALIZED_TIME or %ASN1_ETYPE_UTC_TIME
+ * @der: DER data to decode containing the time
+ * @der_len: Length of DER data to decode.
+ * @ret_len: Output variable containing the length of the DER data.
+ * @str: Pre-allocated output buffer to put the textual time in.
+ * @str_size: Length of pre-allocated output buffer.
+ * @flags: Zero or %ASN1_DECODE_FLAG_STRICT_DER
+ *
+ * Performs basic checks in the DER encoded time object and returns its textual form.
+ * The textual form will be in the YYYYMMDD000000Z format for GeneralizedTime
+ * and YYMMDD000000Z for UTCTime.
+ *
+ * Returns: %ASN1_SUCCESS on success, or an error.
+ -*/
+static int
+_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len,
+ int *ret_len, char *str, int str_size, unsigned flags)
+{
+ int len_len, str_len;
+ unsigned i;
+ unsigned sign_count = 0;
+ unsigned dot_count = 0;
+ const unsigned char *p;
+
+ if (der_len <= 0 || str == NULL)
+ return ASN1_DER_ERROR;
+
+ str_len = asn1_get_length_der (der, der_len, &len_len);
+ if (str_len <= 0 || str_size < str_len)
+ return ASN1_DER_ERROR;
+
+ /* perform some sanity checks on the data */
+ if (str_len < 8)
+ {
+ warn ();
+ return ASN1_TIME_ENCODING_ERROR;
+ }
+
+ if ((flags & ASN1_DECODE_FLAG_STRICT_DER)
+ && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME))
+ {
+ p = &der[len_len];
+ for (i = 0; i < (unsigned) (str_len - 1); i++)
+ {
+ if (c_isdigit (p[i]) == 0)
+ {
+ if (type == ASN1_ETYPE_GENERALIZED_TIME)
+ {
+ /* tolerate lax encodings */
+ if (p[i] == '.' && dot_count == 0)
+ {
+ dot_count++;
+ continue;
+ }
+
+ /* This is not really valid DER, but there are
+ * structures using that */
+ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) &&
+ (p[i] == '+' || p[i] == '-') && sign_count == 0)
+ {
+ sign_count++;
+ continue;
+ }
+ }
+
+ warn ();
+ return ASN1_TIME_ENCODING_ERROR;
+ }
+ }
+
+ if (sign_count == 0 && p[str_len - 1] != 'Z')
+ {
+ warn ();
+ return ASN1_TIME_ENCODING_ERROR;
+ }
+ }
+ memcpy (str, der + len_len, str_len);
+ str[str_len] = 0;
+ *ret_len = str_len + len_len;
+
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_get_object_id_der:
+ * @der: DER data to decode containing the OBJECT IDENTIFIER
+ * @der_len: Length of DER data to decode.
+ * @ret_len: Output variable containing the length of the DER data.
+ * @str: Pre-allocated output buffer to put the textual object id in.
+ * @str_size: Length of pre-allocated output buffer.
+ *
+ * Converts a DER encoded object identifier to its textual form. This
+ * function expects the DER object identifier without the tag.
+ *
+ * Returns: %ASN1_SUCCESS on success, or an error.
+ **/
+int
+asn1_get_object_id_der (const unsigned char *der, int der_len, int *ret_len,
+ char *str, int str_size)
+{
+ int len_len, len, k;
+ int leading, parsed;
+ char temp[LTOSTR_MAX_SIZE];
+ uint64_t val, val1, val0;
+
+ *ret_len = 0;
+ if (str && str_size > 0)
+ str[0] = 0; /* no oid */
+
+ if (str == NULL || der_len <= 0)
+ return ASN1_GENERIC_ERROR;
+
+ len = asn1_get_length_der (der, der_len, &len_len);
+
+ if (len <= 0 || len + len_len > der_len)
+ return ASN1_DER_ERROR;
+
+ /* leading octet can never be 0x80 */
+ if (der[len_len] == 0x80)
+ return ASN1_DER_ERROR;
+
+ val0 = 0;
+
+ for (k = 0; k < len; k++)
+ {
+ if (INT_LEFT_SHIFT_OVERFLOW (val0, 7))
+ return ASN1_DER_ERROR;
+
+ val0 <<= 7;
+ val0 |= der[len_len + k] & 0x7F;
+ if (!(der[len_len + k] & 0x80))
+ break;
+ }
+ parsed = ++k;
+
+ /* val0 = (X*40) + Y, X={0,1,2}, Y<=39 when X={0,1} */
+ /* X = val, Y = val1 */
+
+ /* check if X == 0 */
+ val = 0;
+ val1 = val0;
+ if (val1 > 39)
+ {
+ val = 1;
+ val1 = val0 - 40;
+ if (val1 > 39)
+ {
+ val = 2;
+ val1 = val0 - 80;
+ }
+ }
+
+ _asn1_str_cpy (str, str_size, _asn1_ltostr (val, temp));
+ _asn1_str_cat (str, str_size, ".");
+ _asn1_str_cat (str, str_size, _asn1_ltostr (val1, temp));
+
+ val = 0;
+ leading = 1;
+ for (k = parsed; k < len; k++)
+ {
+ /* X.690 mandates that the leading byte must never be 0x80
+ */
+ if (leading != 0 && der[len_len + k] == 0x80)
+ return ASN1_DER_ERROR;
+ leading = 0;
+
+ /* check for wrap around */
+ if (INT_LEFT_SHIFT_OVERFLOW (val, 7))
+ return ASN1_DER_ERROR;
+
+ val = val << 7;
+ val |= der[len_len + k] & 0x7F;
+
+ if (!(der[len_len + k] & 0x80))
+ {
+ _asn1_str_cat (str, str_size, ".");
+ _asn1_str_cat (str, str_size, _asn1_ltostr (val, temp));
+ val = 0;
+ leading = 1;
+ }
+ }
+
+ if (INT_ADD_OVERFLOW (len, len_len))
+ return ASN1_DER_ERROR;
+
+ *ret_len = len + len_len;
+
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_get_bit_der:
+ * @der: DER data to decode containing the BIT SEQUENCE.
+ * @der_len: Length of DER data to decode.
+ * @ret_len: Output variable containing the length of the DER data.
+ * @str: Pre-allocated output buffer to put decoded BIT SEQUENCE in.
+ * @str_size: Length of pre-allocated output buffer.
+ * @bit_len: Output variable containing the size of the BIT SEQUENCE.
+ *
+ * Extract a BIT SEQUENCE from DER data.
+ *
+ * Returns: %ASN1_SUCCESS on success, or an error.
+ **/
+int
+asn1_get_bit_der (const unsigned char *der, int der_len,
+ int *ret_len, unsigned char *str, int str_size,
+ int *bit_len)
+{
+ int len_len = 0, len_byte;
+
+ if (der_len <= 0)
+ return ASN1_GENERIC_ERROR;
+
+ len_byte = asn1_get_length_der (der, der_len, &len_len) - 1;
+ if (len_byte < 0)
+ return ASN1_DER_ERROR;
+
+ *ret_len = len_byte + len_len + 1;
+ *bit_len = len_byte * 8 - der[len_len];
+
+ if (*bit_len < 0)
+ return ASN1_DER_ERROR;
+
+ if (str_size >= len_byte)
+ {
+ if (len_byte > 0 && str)
+ memcpy (str, der + len_len + 1, len_byte);
+ }
+ else
+ {
+ return ASN1_MEM_ERROR;
+ }
+
+ return ASN1_SUCCESS;
+}
+
+/* tag_len: the total tag length (explicit+inner)
+ * inner_tag_len: the inner_tag length
+ */
+static int
+_asn1_extract_tag_der (asn1_node node, const unsigned char *der, int der_len,
+ int *tag_len, int *inner_tag_len, unsigned flags)
+{
+ asn1_node p;
+ int counter, len2, len3, is_tag_implicit;
+ int result;
+ unsigned long tag, tag_implicit = 0;
+ unsigned char class, class2, class_implicit = 0;
+
+ if (der_len <= 0)
+ return ASN1_GENERIC_ERROR;
+
+ counter = is_tag_implicit = 0;
+
+ if (node->type & CONST_TAG)
+ {
+ p = node->down;
+ while (p)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_TAG)
+ {
+ if (p->type & CONST_APPLICATION)
+ class2 = ASN1_CLASS_APPLICATION;
+ else if (p->type & CONST_UNIVERSAL)
+ class2 = ASN1_CLASS_UNIVERSAL;
+ else if (p->type & CONST_PRIVATE)
+ class2 = ASN1_CLASS_PRIVATE;
+ else
+ class2 = ASN1_CLASS_CONTEXT_SPECIFIC;
+
+ if (p->type & CONST_EXPLICIT)
+ {
+ if (asn1_get_tag_der
+ (der + counter, der_len, &class, &len2,
+ &tag) != ASN1_SUCCESS)
+ return ASN1_DER_ERROR;
+
+ DECR_LEN (der_len, len2);
+ counter += len2;
+
+ if (flags & ASN1_DECODE_FLAG_STRICT_DER)
+ len3 =
+ asn1_get_length_der (der + counter, der_len, &len2);
+ else
+ len3 =
+ asn1_get_length_ber (der + counter, der_len, &len2);
+ if (len3 < 0)
+ return ASN1_DER_ERROR;
+
+ DECR_LEN (der_len, len2);
+ counter += len2;
+
+ if (!is_tag_implicit)
+ {
+ if ((class != (class2 | ASN1_CLASS_STRUCTURED)) ||
+ (tag != strtoul ((char *) p->value, NULL, 10)))
+ return ASN1_TAG_ERROR;
+ }
+ else
+ { /* ASN1_TAG_IMPLICIT */
+ if ((class != class_implicit) || (tag != tag_implicit))
+ return ASN1_TAG_ERROR;
+ }
+ is_tag_implicit = 0;
+ }
+ else
+ { /* ASN1_TAG_IMPLICIT */
+ if (!is_tag_implicit)
+ {
+ if ((type_field (node->type) == ASN1_ETYPE_SEQUENCE) ||
+ (type_field (node->type) == ASN1_ETYPE_SEQUENCE_OF)
+ || (type_field (node->type) == ASN1_ETYPE_SET)
+ || (type_field (node->type) == ASN1_ETYPE_SET_OF))
+ class2 |= ASN1_CLASS_STRUCTURED;
+ class_implicit = class2;
+ tag_implicit = strtoul ((char *) p->value, NULL, 10);
+ is_tag_implicit = 1;
+ }
+ }
+ }
+ p = p->right;
+ }
+ }
+
+ if (is_tag_implicit)
+ {
+ if (asn1_get_tag_der
+ (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS)
+ return ASN1_DER_ERROR;
+
+ DECR_LEN (der_len, len2);
+
+ if ((class != class_implicit) || (tag != tag_implicit))
+ {
+ if (type_field (node->type) == ASN1_ETYPE_OCTET_STRING)
+ {
+ class_implicit |= ASN1_CLASS_STRUCTURED;
+ if ((class != class_implicit) || (tag != tag_implicit))
+ return ASN1_TAG_ERROR;
+ }
+ else
+ return ASN1_TAG_ERROR;
+ }
+ }
+ else
+ {
+ unsigned type = type_field (node->type);
+ if (type == ASN1_ETYPE_TAG)
+ {
+ *tag_len = 0;
+ if (inner_tag_len)
+ *inner_tag_len = 0;
+ return ASN1_SUCCESS;
+ }
+
+ if (asn1_get_tag_der
+ (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS)
+ return ASN1_DER_ERROR;
+
+ DECR_LEN (der_len, len2);
+
+ switch (type)
+ {
+ case ASN1_ETYPE_NULL:
+ case ASN1_ETYPE_BOOLEAN:
+ case ASN1_ETYPE_INTEGER:
+ case ASN1_ETYPE_ENUMERATED:
+ case ASN1_ETYPE_OBJECT_ID:
+ case ASN1_ETYPE_GENERALSTRING:
+ case ASN1_ETYPE_NUMERIC_STRING:
+ case ASN1_ETYPE_IA5_STRING:
+ case ASN1_ETYPE_TELETEX_STRING:
+ case ASN1_ETYPE_PRINTABLE_STRING:
+ case ASN1_ETYPE_UNIVERSAL_STRING:
+ case ASN1_ETYPE_BMP_STRING:
+ case ASN1_ETYPE_UTF8_STRING:
+ case ASN1_ETYPE_VISIBLE_STRING:
+ case ASN1_ETYPE_BIT_STRING:
+ case ASN1_ETYPE_SEQUENCE:
+ case ASN1_ETYPE_SEQUENCE_OF:
+ case ASN1_ETYPE_SET:
+ case ASN1_ETYPE_SET_OF:
+ case ASN1_ETYPE_GENERALIZED_TIME:
+ case ASN1_ETYPE_UTC_TIME:
+ if ((class != _asn1_tags[type].class)
+ || (tag != _asn1_tags[type].tag))
+ return ASN1_DER_ERROR;
+ break;
+
+ case ASN1_ETYPE_OCTET_STRING:
+ /* OCTET STRING is handled differently to allow
+ * BER encodings (structured class). */
+ if (((class != ASN1_CLASS_UNIVERSAL)
+ && (class != (ASN1_CLASS_UNIVERSAL | ASN1_CLASS_STRUCTURED)))
+ || (tag != ASN1_TAG_OCTET_STRING))
+ return ASN1_DER_ERROR;
+ break;
+ case ASN1_ETYPE_ANY:
+ counter -= len2;
+ break;
+ case ASN1_ETYPE_CHOICE:
+ counter -= len2;
+ break;
+ default:
+ return ASN1_DER_ERROR;
+ break;
+ }
+ }
+
+ counter += len2;
+ *tag_len = counter;
+ if (inner_tag_len)
+ *inner_tag_len = len2;
+ return ASN1_SUCCESS;
+
+cleanup:
+ return result;
+}
+
+static int
+extract_tag_der_recursive (asn1_node node, const unsigned char *der,
+ int der_len, int *ret_len, int *inner_len,
+ unsigned flags)
+{
+ asn1_node p;
+ int ris = ASN1_DER_ERROR;
+
+ if (type_field (node->type) == ASN1_ETYPE_CHOICE)
+ {
+ p = node->down;
+ while (p)
+ {
+ ris =
+ _asn1_extract_tag_der (p, der, der_len, ret_len, inner_len,
+ flags);
+ if (ris == ASN1_SUCCESS)
+ break;
+ p = p->right;
+ }
+
+ *ret_len = 0;
+ return ris;
+ }
+ else
+ return _asn1_extract_tag_der (node, der, der_len, ret_len, inner_len,
+ flags);
+}
+
+static int
+_asn1_delete_not_used (asn1_node node)
+{
+ asn1_node p, p2;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node;
+ while (p)
+ {
+ if (p->type & CONST_NOT_USED)
+ {
+ p2 = NULL;
+ if (p != node)
+ {
+ p2 = _asn1_find_left (p);
+ if (!p2)
+ p2 = _asn1_find_up (p);
+ }
+ asn1_delete_structure (&p);
+ p = p2;
+ }
+
+ if (!p)
+ break; /* reach node */
+
+ if (p->down)
+ {
+ p = p->down;
+ }
+ else
+ {
+ if (p == node)
+ p = NULL;
+ else if (p->right)
+ p = p->right;
+ else
+ {
+ while (1)
+ {
+ p = _asn1_find_up (p);
+ if (p == node)
+ {
+ p = NULL;
+ break;
+ }
+ if (p->right)
+ {
+ p = p->right;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return ASN1_SUCCESS;
+}
+
+static int
+_asn1_get_indefinite_length_string (const unsigned char *der,
+ int der_len, int *len)
+{
+ int len2, len3, counter, indefinite;
+ int result;
+ unsigned long tag;
+ unsigned char class;
+
+ counter = indefinite = 0;
+
+ while (1)
+ {
+ if (HAVE_TWO (der_len) && (der[counter] == 0)
+ && (der[counter + 1] == 0))
+ {
+ counter += 2;
+ DECR_LEN (der_len, 2);
+
+ indefinite--;
+ if (indefinite <= 0)
+ break;
+ else
+ continue;
+ }
+
+ if (asn1_get_tag_der
+ (der + counter, der_len, &class, &len2, &tag) != ASN1_SUCCESS)
+ return ASN1_DER_ERROR;
+
+ DECR_LEN (der_len, len2);
+ counter += len2;
+
+ len2 = asn1_get_length_der (der + counter, der_len, &len3);
+ if (len2 < -1)
+ return ASN1_DER_ERROR;
+
+ if (len2 == -1)
+ {
+ indefinite++;
+ counter += 1;
+ DECR_LEN (der_len, 1);
+ }
+ else
+ {
+ counter += len2 + len3;
+ DECR_LEN (der_len, len2 + len3);
+ }
+ }
+
+ *len = counter;
+ return ASN1_SUCCESS;
+
+cleanup:
+ return result;
+}
+
+static void
+delete_unneeded_choice_fields (asn1_node p)
+{
+ asn1_node p2;
+
+ while (p->right)
+ {
+ p2 = p->right;
+ asn1_delete_structure (&p2);
+ }
+}
+
+
+/**
+ * asn1_der_decoding2
+ * @element: pointer to an ASN1 structure.
+ * @ider: vector that contains the DER encoding.
+ * @max_ider_len: pointer to an integer giving the information about the
+ * maximal number of bytes occupied by *@ider. The real size of the DER
+ * encoding is returned through this pointer.
+ * @flags: flags controlling the behaviour of the function.
+ * @errorDescription: null-terminated string contains details when an
+ * error occurred.
+ *
+ * Fill the structure *@element with values of a DER encoding string. The
+ * structure must just be created with function asn1_create_element().
+ *
+ * If %ASN1_DECODE_FLAG_ALLOW_PADDING flag is set then the function will ignore
+ * padding after the decoded DER data. Upon a successful return the value of
+ * *@max_ider_len will be set to the number of bytes decoded.
+ *
+ * If %ASN1_DECODE_FLAG_STRICT_DER flag is set then the function will
+ * not decode any BER-encoded elements.
+ *
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
+ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
+ * %ASN1_DER_ERROR if the der encoding doesn't match the structure
+ * name (*@ELEMENT deleted).
+ **/
+int
+asn1_der_decoding2 (asn1_node * element, const void *ider, int *max_ider_len,
+ unsigned int flags, char *errorDescription)
+{
+ asn1_node node, p, p2, p3;
+ char temp[128];
+ int counter, len2, len3, len4, move, ris, tlen;
+ struct node_tail_cache_st tcache = { NULL, NULL };
+ unsigned char class;
+ unsigned long tag;
+ int tag_len;
+ int indefinite, result, total_len = *max_ider_len, ider_len = *max_ider_len;
+ int inner_tag_len;
+ unsigned char *ptmp;
+ const unsigned char *ptag;
+ const unsigned char *der = ider;
+
+ node = *element;
+
+ if (errorDescription != NULL)
+ errorDescription[0] = 0;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ if (node->type & CONST_OPTION)
+ {
+ result = ASN1_GENERIC_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ counter = 0;
+ move = DOWN;
+ p = node;
+ while (1)
+ {
+ tag_len = 0;
+ inner_tag_len = 0;
+ ris = ASN1_SUCCESS;
+ if (move != UP)
+ {
+ if (p->type & CONST_SET)
+ {
+ p2 = _asn1_find_up (p);
+ len2 = p2->tmp_ival;
+ if (len2 == -1)
+ {
+ if (HAVE_TWO (ider_len) && !der[counter]
+ && !der[counter + 1])
+ {
+ p = p2;
+ move = UP;
+ counter += 2;
+ DECR_LEN (ider_len, 2);
+ continue;
+ }
+ }
+ else if (counter == len2)
+ {
+ p = p2;
+ move = UP;
+ continue;
+ }
+ else if (counter > len2)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ p2 = p2->down;
+ while (p2)
+ {
+ if ((p2->type & CONST_SET) && (p2->type & CONST_NOT_USED))
+ {
+ ris =
+ extract_tag_der_recursive (p2, der + counter,
+ ider_len, &len2, NULL,
+ flags);
+ if (ris == ASN1_SUCCESS)
+ {
+ p2->type &= ~CONST_NOT_USED;
+ p = p2;
+ break;
+ }
+ }
+ p2 = p2->right;
+ }
+ if (p2 == NULL)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ }
+
+ /* the position in the DER structure this starts */
+ p->start = counter;
+ p->end = total_len - 1;
+
+ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
+ {
+ p2 = _asn1_find_up (p);
+ len2 = p2->tmp_ival;
+ if (counter == len2)
+ {
+ if (p->right)
+ {
+ p2 = p->right;
+ move = RIGHT;
+ }
+ else
+ move = UP;
+
+ if (p->type & CONST_OPTION)
+ asn1_delete_structure (&p);
+
+ p = p2;
+ continue;
+ }
+ }
+
+ if (type_field (p->type) == ASN1_ETYPE_CHOICE)
+ {
+ while (p->down)
+ {
+ ris =
+ extract_tag_der_recursive (p->down, der + counter,
+ ider_len, &len2, NULL, flags);
+
+ if (ris == ASN1_SUCCESS)
+ {
+ delete_unneeded_choice_fields (p->down);
+ break;
+ }
+ else if (ris == ASN1_ERROR_TYPE_ANY)
+ {
+ result = ASN1_ERROR_TYPE_ANY;
+ warn ();
+ goto cleanup;
+ }
+ else
+ {
+ p2 = p->down;
+ asn1_delete_structure (&p2);
+ }
+ }
+
+ if (p->down == NULL)
+ {
+ if (!(p->type & CONST_OPTION))
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ }
+ else if (type_field (p->type) != ASN1_ETYPE_CHOICE)
+ p = p->down;
+
+ p->start = counter;
+ }
+
+ if ((p->type & CONST_OPTION) || (p->type & CONST_DEFAULT))
+ {
+ p2 = _asn1_find_up (p);
+ len2 = p2->tmp_ival;
+
+ if ((len2 != -1) && (counter > len2))
+ ris = ASN1_TAG_ERROR;
+ }
+
+ if (ris == ASN1_SUCCESS)
+ ris =
+ extract_tag_der_recursive (p, der + counter, ider_len,
+ &tag_len, &inner_tag_len, flags);
+
+ if (ris != ASN1_SUCCESS)
+ {
+ if (p->type & CONST_OPTION)
+ {
+ p->type |= CONST_NOT_USED;
+ move = RIGHT;
+ }
+ else if (p->type & CONST_DEFAULT)
+ {
+ _asn1_set_value (p, NULL, 0);
+ move = RIGHT;
+ }
+ else
+ {
+ if (errorDescription != NULL)
+ _asn1_error_description_tag_error (p, errorDescription);
+
+ result = ASN1_TAG_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ }
+ else
+ {
+ DECR_LEN (ider_len, tag_len);
+ counter += tag_len;
+ }
+ }
+
+ if (ris == ASN1_SUCCESS)
+ {
+ switch (type_field (p->type))
+ {
+ case ASN1_ETYPE_NULL:
+ DECR_LEN (ider_len, 1);
+ if (der[counter])
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ counter++;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_BOOLEAN:
+ DECR_LEN (ider_len, 2);
+
+ if (der[counter++] != 1)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ if (der[counter++] == 0)
+ _asn1_set_value (p, "F", 1);
+ else
+ _asn1_set_value (p, "T", 1);
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_INTEGER:
+ case ASN1_ETYPE_ENUMERATED:
+ len2 = asn1_get_length_der (der + counter, ider_len, &len3);
+ if (len2 < 0)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len3 + len2);
+
+ _asn1_set_value (p, der + counter, len3 + len2);
+ counter += len3 + len2;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_OBJECT_ID:
+ result =
+ asn1_get_object_id_der (der + counter, ider_len, &len2,
+ temp, sizeof (temp));
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len2);
+
+ tlen = strlen (temp);
+ if (tlen > 0)
+ _asn1_set_value (p, temp, tlen + 1);
+
+ counter += len2;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_GENERALIZED_TIME:
+ case ASN1_ETYPE_UTC_TIME:
+ result =
+ _asn1_get_time_der (type_field (p->type), der + counter,
+ ider_len, &len2, temp, sizeof (temp) - 1,
+ flags);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len2);
+
+ tlen = strlen (temp);
+ if (tlen > 0)
+ _asn1_set_value (p, temp, tlen);
+
+ counter += len2;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_OCTET_STRING:
+ if (counter < inner_tag_len)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ ptag = der + counter - inner_tag_len;
+ if ((flags & ASN1_DECODE_FLAG_STRICT_DER)
+ || !(ptag[0] & ASN1_CLASS_STRUCTURED))
+ {
+ if (ptag[0] & ASN1_CLASS_STRUCTURED)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ len2 = asn1_get_length_der (der + counter, ider_len, &len3);
+ if (len2 < 0)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len3 + len2);
+
+ _asn1_set_value (p, der + counter, len3 + len2);
+ counter += len3 + len2;
+ }
+ else
+ {
+ unsigned dflags = 0, vlen, ber_len;
+
+ if (ptag[0] & ASN1_CLASS_STRUCTURED)
+ dflags |= DECODE_FLAG_CONSTRUCTED;
+
+ result =
+ _asn1_decode_simple_ber (type_field (p->type),
+ der + counter, ider_len, &ptmp,
+ &vlen, &ber_len, dflags);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, ber_len);
+
+ _asn1_set_value_lv (p, ptmp, vlen);
+
+ counter += ber_len;
+ free (ptmp);
+ }
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_GENERALSTRING:
+ case ASN1_ETYPE_NUMERIC_STRING:
+ case ASN1_ETYPE_IA5_STRING:
+ case ASN1_ETYPE_TELETEX_STRING:
+ case ASN1_ETYPE_PRINTABLE_STRING:
+ case ASN1_ETYPE_UNIVERSAL_STRING:
+ case ASN1_ETYPE_BMP_STRING:
+ case ASN1_ETYPE_UTF8_STRING:
+ case ASN1_ETYPE_VISIBLE_STRING:
+ case ASN1_ETYPE_BIT_STRING:
+ len2 = asn1_get_length_der (der + counter, ider_len, &len3);
+ if (len2 < 0)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len3 + len2);
+
+ _asn1_set_value (p, der + counter, len3 + len2);
+ counter += len3 + len2;
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_SEQUENCE:
+ case ASN1_ETYPE_SET:
+ if (move == UP)
+ {
+ len2 = p->tmp_ival;
+ p->tmp_ival = 0;
+ if (len2 == -1)
+ { /* indefinite length method */
+ DECR_LEN (ider_len, 2);
+ if ((der[counter]) || der[counter + 1])
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ counter += 2;
+ }
+ else
+ { /* definite length method */
+ if (len2 != counter)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ }
+ move = RIGHT;
+ }
+ else
+ { /* move==DOWN || move==RIGHT */
+ len3 = asn1_get_length_der (der + counter, ider_len, &len2);
+ if (IS_ERR (len3, flags))
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len2);
+ counter += len2;
+
+ if (len3 > 0)
+ {
+ p->tmp_ival = counter + len3;
+ move = DOWN;
+ }
+ else if (len3 == 0)
+ {
+ p2 = p->down;
+ while (p2)
+ {
+ if (type_field (p2->type) != ASN1_ETYPE_TAG)
+ {
+ p3 = p2->right;
+ asn1_delete_structure (&p2);
+ p2 = p3;
+ }
+ else
+ p2 = p2->right;
+ }
+ move = RIGHT;
+ }
+ else
+ { /* indefinite length method */
+ p->tmp_ival = -1;
+ move = DOWN;
+ }
+ }
+ break;
+ case ASN1_ETYPE_SEQUENCE_OF:
+ case ASN1_ETYPE_SET_OF:
+ if (move == UP)
+ {
+ len2 = p->tmp_ival;
+ if (len2 == -1)
+ { /* indefinite length method */
+ if (!HAVE_TWO (ider_len)
+ || ((der[counter]) || der[counter + 1]))
+ {
+ result = _asn1_append_sequence_set (p, &tcache);
+ if (result != 0)
+ {
+ warn ();
+ goto cleanup;
+ }
+ p = tcache.tail;
+ move = RIGHT;
+ continue;
+ }
+
+ p->tmp_ival = 0;
+ tcache.tail = NULL; /* finished decoding this structure */
+ tcache.head = NULL;
+ DECR_LEN (ider_len, 2);
+ counter += 2;
+ }
+ else
+ { /* definite length method */
+ if (len2 > counter)
+ {
+ result = _asn1_append_sequence_set (p, &tcache);
+ if (result != 0)
+ {
+ warn ();
+ goto cleanup;
+ }
+ p = tcache.tail;
+ move = RIGHT;
+ continue;
+ }
+
+ p->tmp_ival = 0;
+ tcache.tail = NULL; /* finished decoding this structure */
+ tcache.head = NULL;
+
+ if (len2 != counter)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ }
+ }
+ else
+ { /* move==DOWN || move==RIGHT */
+ len3 = asn1_get_length_der (der + counter, ider_len, &len2);
+ if (IS_ERR (len3, flags))
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len2);
+ counter += len2;
+ if (len3)
+ {
+ if (len3 > 0)
+ { /* definite length method */
+ p->tmp_ival = counter + len3;
+ }
+ else
+ { /* indefinite length method */
+ p->tmp_ival = -1;
+ }
+
+ p2 = p->down;
+ if (p2 == NULL)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ while ((type_field (p2->type) == ASN1_ETYPE_TAG)
+ || (type_field (p2->type) == ASN1_ETYPE_SIZE))
+ p2 = p2->right;
+ if (p2->right == NULL)
+ {
+ result = _asn1_append_sequence_set (p, &tcache);
+ if (result != 0)
+ {
+ warn ();
+ goto cleanup;
+ }
+ }
+ p = p2;
+ }
+ }
+ move = RIGHT;
+ break;
+ case ASN1_ETYPE_ANY:
+ /* Check indefinite lenth method in an EXPLICIT TAG */
+
+ if (!(flags & ASN1_DECODE_FLAG_STRICT_DER)
+ && (p->type & CONST_TAG) && tag_len == 2
+ && (der[counter - 1] == 0x80))
+ indefinite = 1;
+ else
+ indefinite = 0;
+
+ if (asn1_get_tag_der
+ (der + counter, ider_len, &class, &len2,
+ &tag) != ASN1_SUCCESS)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len2);
+
+ len4 =
+ asn1_get_length_der (der + counter + len2, ider_len, &len3);
+ if (IS_ERR (len4, flags))
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ if (len4 != -1) /* definite */
+ {
+ len2 += len4;
+
+ DECR_LEN (ider_len, len4 + len3);
+ _asn1_set_value_lv (p, der + counter, len2 + len3);
+ counter += len2 + len3;
+ }
+ else /* == -1 */
+ { /* indefinite length */
+ ider_len += len2; /* undo DECR_LEN */
+
+ if (counter == 0)
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+
+ result =
+ _asn1_get_indefinite_length_string (der + counter,
+ ider_len, &len2);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ DECR_LEN (ider_len, len2);
+ _asn1_set_value_lv (p, der + counter, len2);
+ counter += len2;
+
+ }
+
+ /* Check if a couple of 0x00 are present due to an EXPLICIT TAG with
+ an indefinite length method. */
+ if (indefinite)
+ {
+ DECR_LEN (ider_len, 2);
+ if (!der[counter] && !der[counter + 1])
+ {
+ counter += 2;
+ }
+ else
+ {
+ result = ASN1_DER_ERROR;
+ warn ();
+ goto cleanup;
+ }
+ }
+
+ move = RIGHT;
+ break;
+ default:
+ move = (move == UP) ? RIGHT : DOWN;
+ break;
+ }
+ }
+
+ if (p)
+ {
+ p->end = counter - 1;
+ }
+
+ if (p == node && move != DOWN)
+ break;
+
+ if (move == DOWN)
+ {
+ if (p->down)
+ p = p->down;
+ else
+ move = RIGHT;
+ }
+ if ((move == RIGHT) && !(p->type & CONST_SET))
+ {
+ if (p->right)
+ p = p->right;
+ else
+ move = UP;
+ }
+ if (move == UP)
+ p = _asn1_find_up (p);
+ }
+
+ _asn1_delete_not_used (*element);
+
+ if ((ider_len < 0) ||
+ (!(flags & ASN1_DECODE_FLAG_ALLOW_PADDING) && (ider_len != 0)))
+ {
+ warn ();
+ result = ASN1_DER_ERROR;
+ goto cleanup;
+ }
+
+ *max_ider_len = total_len - ider_len;
+
+ return ASN1_SUCCESS;
+
+cleanup:
+ asn1_delete_structure (element);
+ return result;
+}
+
+
+/**
+ * asn1_der_decoding:
+ * @element: pointer to an ASN1 structure.
+ * @ider: vector that contains the DER encoding.
+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1].
+ * @errorDescription: null-terminated string contains details when an
+ * error occurred.
+ *
+ * Fill the structure *@element with values of a DER encoding
+ * string. The structure must just be created with function
+ * asn1_create_element().
+ *
+ * Note that the *@element variable is provided as a pointer for
+ * historical reasons.
+ *
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
+ * if @ELEMENT is %NULL, and %ASN1_TAG_ERROR or
+ * %ASN1_DER_ERROR if the der encoding doesn't match the structure
+ * name (*@ELEMENT deleted).
+ **/
+int
+asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
+ char *errorDescription)
+{
+ return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
+}
+
+/**
+ * asn1_der_decoding_element:
+ * @structure: pointer to an ASN1 structure
+ * @elementName: name of the element to fill
+ * @ider: vector that contains the DER encoding of the whole structure.
+ * @len: number of bytes of *der: der[0]..der[len-1]
+ * @errorDescription: null-terminated string contains details when an
+ * error occurred.
+ *
+ * Fill the element named @ELEMENTNAME with values of a DER encoding
+ * string. The structure must just be created with function
+ * asn1_create_element(). The DER vector must contain the encoding
+ * string of the whole @STRUCTURE. If an error occurs during the
+ * decoding procedure, the *@STRUCTURE is deleted and set equal to
+ * %NULL.
+ *
+ * This function is deprecated and may just be an alias to asn1_der_decoding
+ * in future versions. Use asn1_der_decoding() instead.
+ *
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
+ * if ELEMENT is %NULL or @elementName == NULL, and
+ * %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding doesn't
+ * match the structure @structure (*ELEMENT deleted).
+ **/
+int
+asn1_der_decoding_element (asn1_node * structure, const char *elementName,
+ const void *ider, int len, char *errorDescription)
+{
+ return asn1_der_decoding (structure, ider, len, errorDescription);
+}
+
+/**
+ * asn1_der_decoding_startEnd:
+ * @element: pointer to an ASN1 element
+ * @ider: vector that contains the DER encoding.
+ * @ider_len: number of bytes of *@ider: @ider[0]..@ider[len-1]
+ * @name_element: an element of NAME structure.
+ * @start: the position of the first byte of NAME_ELEMENT decoding
+ * (@ider[*start])
+ * @end: the position of the last byte of NAME_ELEMENT decoding
+ * (@ider[*end])
+ *
+ * Find the start and end point of an element in a DER encoding
+ * string. I mean that if you have a der encoding and you have already
+ * used the function asn1_der_decoding() to fill a structure, it may
+ * happen that you want to find the piece of string concerning an
+ * element of the structure.
+ *
+ * One example is the sequence "tbsCertificate" inside an X509
+ * certificate.
+ *
+ * Note that since libtasn1 3.7 the @ider and @ider_len parameters
+ * can be omitted, if the element is already decoded using asn1_der_decoding().
+ *
+ * Returns: %ASN1_SUCCESS if DER encoding OK, %ASN1_ELEMENT_NOT_FOUND
+ * if ELEMENT is %asn1_node EMPTY or @name_element is not a valid
+ * element, %ASN1_TAG_ERROR or %ASN1_DER_ERROR if the der encoding
+ * doesn't match the structure ELEMENT.
+ **/
+int
+asn1_der_decoding_startEnd (asn1_node element, const void *ider, int ider_len,
+ const char *name_element, int *start, int *end)
+{
+ asn1_node node, node_to_find;
+ int result = ASN1_DER_ERROR;
+
+ node = element;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ node_to_find = asn1_find_node (node, name_element);
+
+ if (node_to_find == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ *start = node_to_find->start;
+ *end = node_to_find->end;
+
+ if (*start == 0 && *end == 0)
+ {
+ if (ider == NULL || ider_len == 0)
+ return ASN1_GENERIC_ERROR;
+
+ /* it seems asn1_der_decoding() wasn't called before. Do it now */
+ result = asn1_der_decoding (&node, ider, ider_len, NULL);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ return result;
+ }
+
+ node_to_find = asn1_find_node (node, name_element);
+ if (node_to_find == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ *start = node_to_find->start;
+ *end = node_to_find->end;
+ }
+
+ if (*end < *start)
+ return ASN1_GENERIC_ERROR;
+
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_expand_any_defined_by:
+ * @definitions: ASN1 definitions
+ * @element: pointer to an ASN1 structure
+ *
+ * Expands every "ANY DEFINED BY" element of a structure created from
+ * a DER decoding process (asn1_der_decoding function). The element
+ * ANY must be defined by an OBJECT IDENTIFIER. The type used to
+ * expand the element ANY is the first one following the definition of
+ * the actual value of the OBJECT IDENTIFIER.
+ *
+ * Returns: %ASN1_SUCCESS if Substitution OK, %ASN1_ERROR_TYPE_ANY if
+ * some "ANY DEFINED BY" element couldn't be expanded due to a
+ * problem in OBJECT_ID -> TYPE association, or other error codes
+ * depending on DER decoding.
+ **/
+int
+asn1_expand_any_defined_by (asn1_node_const definitions, asn1_node * element)
+{
+ char name[2 * ASN1_MAX_NAME_SIZE + 2], value[ASN1_MAX_NAME_SIZE];
+ int retCode = ASN1_SUCCESS, result;
+ int len, len2, len3;
+ asn1_node_const p2;
+ asn1_node p, p3, aux = NULL;
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+ const char *definitionsName;
+
+ if ((definitions == NULL) || (*element == NULL))
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ definitionsName = definitions->name;
+
+ p = *element;
+ while (p)
+ {
+
+ switch (type_field (p->type))
+ {
+ case ASN1_ETYPE_ANY:
+ if ((p->type & CONST_DEFINED_BY) && (p->value))
+ {
+ /* search the "DEF_BY" element */
+ p2 = p->down;
+ while ((p2) && (type_field (p2->type) != ASN1_ETYPE_CONSTANT))
+ p2 = p2->right;
+
+ if (!p2)
+ {
+ retCode = ASN1_ERROR_TYPE_ANY;
+ break;
+ }
+
+ p3 = _asn1_find_up (p);
+
+ if (!p3)
+ {
+ retCode = ASN1_ERROR_TYPE_ANY;
+ break;
+ }
+
+ p3 = p3->down;
+ while (p3)
+ {
+ if (!(strcmp (p3->name, p2->name)))
+ break;
+ p3 = p3->right;
+ }
+
+ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
+ (p3->value == NULL))
+ {
+
+ p3 = _asn1_find_up (p);
+ p3 = _asn1_find_up (p3);
+
+ if (!p3)
+ {
+ retCode = ASN1_ERROR_TYPE_ANY;
+ break;
+ }
+
+ p3 = p3->down;
+
+ while (p3)
+ {
+ if (!(strcmp (p3->name, p2->name)))
+ break;
+ p3 = p3->right;
+ }
+
+ if ((!p3) || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
+ || (p3->value == NULL))
+ {
+ retCode = ASN1_ERROR_TYPE_ANY;
+ break;
+ }
+ }
+
+ /* search the OBJECT_ID into definitions */
+ p2 = definitions->down;
+ while (p2)
+ {
+ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
+ (p2->type & CONST_ASSIGN))
+ {
+ snprintf (name, sizeof (name), "%s.%s", definitionsName,
+ p2->name);
+
+ len = ASN1_MAX_NAME_SIZE;
+ result =
+ asn1_read_value (definitions, name, value, &len);
+
+ if ((result == ASN1_SUCCESS)
+ && (!_asn1_strcmp (p3->value, value)))
+ {
+ p2 = p2->right; /* pointer to the structure to
+ use for expansion */
+ while ((p2) && (p2->type & CONST_ASSIGN))
+ p2 = p2->right;
+
+ if (p2)
+ {
+ snprintf (name, sizeof (name), "%s.%s",
+ definitionsName, p2->name);
+
+ result =
+ asn1_create_element (definitions, name, &aux);
+ if (result == ASN1_SUCCESS)
+ {
+ _asn1_cpy_name (aux, p);
+ len2 =
+ asn1_get_length_der (p->value,
+ p->value_len, &len3);
+ if (len2 < 0)
+ return ASN1_DER_ERROR;
+
+ result =
+ asn1_der_decoding (&aux, p->value + len3,
+ len2,
+ errorDescription);
+ if (result == ASN1_SUCCESS)
+ {
+
+ _asn1_set_right (aux, p->right);
+ _asn1_set_right (p, aux);
+
+ result = asn1_delete_structure (&p);
+ if (result == ASN1_SUCCESS)
+ {
+ p = aux;
+ aux = NULL;
+ break;
+ }
+ else
+ { /* error with asn1_delete_structure */
+ asn1_delete_structure (&aux);
+ retCode = result;
+ break;
+ }
+ }
+ else
+ { /* error with asn1_der_decoding */
+ retCode = result;
+ break;
+ }
+ }
+ else
+ { /* error with asn1_create_element */
+ retCode = result;
+ break;
+ }
+ }
+ else
+ { /* error with the pointer to the structure to exapand */
+ retCode = ASN1_ERROR_TYPE_ANY;
+ break;
+ }
+ }
+ }
+ p2 = p2->right;
+ } /* end while */
+
+ if (!p2)
+ {
+ retCode = ASN1_ERROR_TYPE_ANY;
+ break;
+ }
+
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ if (p->down)
+ {
+ p = p->down;
+ }
+ else if (p == *element)
+ {
+ p = NULL;
+ break;
+ }
+ else if (p->right)
+ p = p->right;
+ else
+ {
+ while (1)
+ {
+ p = _asn1_find_up (p);
+ if (p == *element)
+ {
+ p = NULL;
+ break;
+ }
+ if (p->right)
+ {
+ p = p->right;
+ break;
+ }
+ }
+ }
+ }
+
+ return retCode;
+}
+
+/**
+ * asn1_expand_octet_string:
+ * @definitions: ASN1 definitions
+ * @element: pointer to an ASN1 structure
+ * @octetName: name of the OCTECT STRING field to expand.
+ * @objectName: name of the OBJECT IDENTIFIER field to use to define
+ * the type for expansion.
+ *
+ * Expands an "OCTET STRING" element of a structure created from a DER
+ * decoding process (the asn1_der_decoding() function). The type used
+ * for expansion is the first one following the definition of the
+ * actual value of the OBJECT IDENTIFIER indicated by OBJECTNAME.
+ *
+ * Returns: %ASN1_SUCCESS if substitution OK, %ASN1_ELEMENT_NOT_FOUND
+ * if @objectName or @octetName are not correct,
+ * %ASN1_VALUE_NOT_VALID if it wasn't possible to find the type to
+ * use for expansion, or other errors depending on DER decoding.
+ **/
+int
+asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
+ const char *octetName, const char *objectName)
+{
+ char name[2 * ASN1_MAX_NAME_SIZE + 1], value[ASN1_MAX_NAME_SIZE];
+ int retCode = ASN1_SUCCESS, result;
+ int len, len2, len3;
+ asn1_node_const p2;
+ asn1_node aux = NULL;
+ asn1_node octetNode = NULL, objectNode = NULL;
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+
+ if ((definitions == NULL) || (*element == NULL))
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ octetNode = asn1_find_node (*element, octetName);
+ if (octetNode == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+ if (type_field (octetNode->type) != ASN1_ETYPE_OCTET_STRING)
+ return ASN1_ELEMENT_NOT_FOUND;
+ if (octetNode->value == NULL)
+ return ASN1_VALUE_NOT_FOUND;
+
+ objectNode = asn1_find_node (*element, objectName);
+ if (objectNode == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ if (type_field (objectNode->type) != ASN1_ETYPE_OBJECT_ID)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ if (objectNode->value == NULL)
+ return ASN1_VALUE_NOT_FOUND;
+
+
+ /* search the OBJECT_ID into definitions */
+ p2 = definitions->down;
+ while (p2)
+ {
+ if ((type_field (p2->type) == ASN1_ETYPE_OBJECT_ID) &&
+ (p2->type & CONST_ASSIGN))
+ {
+ strcpy (name, definitions->name);
+ strcat (name, ".");
+ strcat (name, p2->name);
+
+ len = sizeof (value);
+ result = asn1_read_value (definitions, name, value, &len);
+
+ if ((result == ASN1_SUCCESS)
+ && (!_asn1_strcmp (objectNode->value, value)))
+ {
+
+ p2 = p2->right; /* pointer to the structure to
+ use for expansion */
+ while ((p2) && (p2->type & CONST_ASSIGN))
+ p2 = p2->right;
+
+ if (p2)
+ {
+ strcpy (name, definitions->name);
+ strcat (name, ".");
+ strcat (name, p2->name);
+
+ result = asn1_create_element (definitions, name, &aux);
+ if (result == ASN1_SUCCESS)
+ {
+ _asn1_cpy_name (aux, octetNode);
+ len2 =
+ asn1_get_length_der (octetNode->value,
+ octetNode->value_len, &len3);
+ if (len2 < 0)
+ return ASN1_DER_ERROR;
+
+ result =
+ asn1_der_decoding (&aux, octetNode->value + len3,
+ len2, errorDescription);
+ if (result == ASN1_SUCCESS)
+ {
+
+ _asn1_set_right (aux, octetNode->right);
+ _asn1_set_right (octetNode, aux);
+
+ result = asn1_delete_structure (&octetNode);
+ if (result == ASN1_SUCCESS)
+ {
+ aux = NULL;
+ break;
+ }
+ else
+ { /* error with asn1_delete_structure */
+ asn1_delete_structure (&aux);
+ retCode = result;
+ break;
+ }
+ }
+ else
+ { /* error with asn1_der_decoding */
+ retCode = result;
+ break;
+ }
+ }
+ else
+ { /* error with asn1_create_element */
+ retCode = result;
+ break;
+ }
+ }
+ else
+ { /* error with the pointer to the structure to exapand */
+ retCode = ASN1_VALUE_NOT_VALID;
+ break;
+ }
+ }
+ }
+
+ p2 = p2->right;
+
+ }
+
+ if (!p2)
+ retCode = ASN1_VALUE_NOT_VALID;
+
+ return retCode;
+}
+
+/*-
+ * _asn1_decode_simple_der:
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
+ * @der: the encoded string
+ * @_der_len: the bytes of the encoded string
+ * @str: a pointer to the data
+ * @str_len: the length of the data
+ * @dflags: DECODE_FLAG_*
+ *
+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
+ * The output is a pointer inside the @der.
+ *
+ * Returns: %ASN1_SUCCESS if successful or an error value.
+ -*/
+static int
+_asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len, const unsigned char **str,
+ unsigned int *str_len, unsigned dflags)
+{
+ int tag_len, len_len;
+ const unsigned char *p;
+ int der_len = _der_len;
+ unsigned char class;
+ unsigned long tag;
+ long ret;
+
+ if (der == NULL || der_len == 0)
+ return ASN1_VALUE_NOT_VALID;
+
+ if (ETYPE_OK (etype) == 0 || ETYPE_IS_STRING (etype) == 0)
+ return ASN1_VALUE_NOT_VALID;
+
+ /* doesn't handle constructed classes */
+ class = ETYPE_CLASS (etype);
+ if (class != ASN1_CLASS_UNIVERSAL)
+ return ASN1_VALUE_NOT_VALID;
+
+ p = der;
+
+ if (dflags & DECODE_FLAG_HAVE_TAG)
+ {
+ ret = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+
+ if (class != ETYPE_CLASS (etype) || tag != ETYPE_TAG (etype))
+ {
+ warn ();
+ return ASN1_DER_ERROR;
+ }
+
+ p += tag_len;
+ der_len -= tag_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
+ }
+
+ ret = asn1_get_length_der (p, der_len, &len_len);
+ if (ret < 0)
+ return ASN1_DER_ERROR;
+
+ p += len_len;
+ der_len -= len_len;
+ if (der_len <= 0)
+ return ASN1_DER_ERROR;
+
+ *str_len = ret;
+ *str = p;
+
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_decode_simple_der:
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
+ * @der: the encoded string
+ * @_der_len: the bytes of the encoded string
+ * @str: a pointer to the data
+ * @str_len: the length of the data
+ *
+ * Decodes a simple DER encoded type (e.g. a string, which is not constructed).
+ * The output is a pointer inside the @der.
+ *
+ * Returns: %ASN1_SUCCESS if successful or an error value.
+ **/
+int
+asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len, const unsigned char **str,
+ unsigned int *str_len)
+{
+ return _asn1_decode_simple_der (etype, der, _der_len, str, str_len,
+ DECODE_FLAG_HAVE_TAG);
+}
+
+static int
+append (uint8_t ** dst, unsigned *dst_size, const unsigned char *src,
+ unsigned src_size)
+{
+ if (src_size == 0)
+ return ASN1_SUCCESS;
+
+ *dst = _asn1_realloc (*dst, *dst_size + src_size);
+ if (*dst == NULL)
+ return ASN1_MEM_ALLOC_ERROR;
+ memcpy (*dst + *dst_size, src, src_size);
+ *dst_size += src_size;
+ return ASN1_SUCCESS;
+}
+
+/*-
+ * _asn1_decode_simple_ber:
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
+ * @der: the encoded string
+ * @_der_len: the bytes of the encoded string
+ * @str: a pointer to the data
+ * @str_len: the length of the data
+ * @ber_len: the total length occupied by BER (may be %NULL)
+ * @have_tag: whether a DER tag is included
+ *
+ * Decodes a BER encoded type. The output is an allocated value
+ * of the data. This decodes BER STRINGS only. Other types are
+ * decoded as DER.
+ *
+ * Returns: %ASN1_SUCCESS if successful or an error value.
+ -*/
+static int
+_asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len, unsigned char **str,
+ unsigned int *str_len, unsigned int *ber_len,
+ unsigned dflags)
+{
+ int tag_len, len_len;
+ const unsigned char *p;
+ int der_len = _der_len;
+ uint8_t *total = NULL;
+ unsigned total_size = 0;
+ unsigned char class;
+ unsigned long tag;
+ unsigned char *out = NULL;
+ const unsigned char *cout = NULL;
+ unsigned out_len;
+ long result;
+
+ if (ber_len)
+ *ber_len = 0;
+
+ if (der == NULL || der_len == 0)
+ {
+ warn ();
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ if (ETYPE_OK (etype) == 0)
+ {
+ warn ();
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ /* doesn't handle constructed + definite classes */
+ class = ETYPE_CLASS (etype);
+ if (class != ASN1_CLASS_UNIVERSAL)
+ {
+ warn ();
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ p = der;
+
+ if (dflags & DECODE_FLAG_HAVE_TAG)
+ {
+ result = asn1_get_tag_der (p, der_len, &class, &tag_len, &tag);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ return result;
+ }
+
+ if (tag != ETYPE_TAG (etype))
+ {
+ warn ();
+ return ASN1_DER_ERROR;
+ }
+
+ p += tag_len;
+
+ DECR_LEN (der_len, tag_len);
+
+ if (ber_len)
+ *ber_len += tag_len;
+ }
+
+ /* indefinite constructed */
+ if ((((dflags & DECODE_FLAG_CONSTRUCTED) || class == ASN1_CLASS_STRUCTURED)
+ && ETYPE_IS_STRING (etype)) && !(dflags & DECODE_FLAG_LEVEL3))
+ {
+ if (der_len == 0)
+ {
+ warn ();
+ result = ASN1_DER_ERROR;
+ goto cleanup;
+ }
+
+ if (der_len > 0 && p[0] == 0x80) /* indefinite */
+ {
+ len_len = 1;
+ DECR_LEN (der_len, len_len);
+ p += len_len;
+
+ if (ber_len)
+ *ber_len += len_len;
+
+ /* decode the available octet strings */
+ do
+ {
+ unsigned tmp_len;
+ unsigned flags = DECODE_FLAG_HAVE_TAG;
+
+ if (dflags & DECODE_FLAG_LEVEL1)
+ flags |= DECODE_FLAG_LEVEL2;
+ else if (dflags & DECODE_FLAG_LEVEL2)
+ flags |= DECODE_FLAG_LEVEL3;
+ else
+ flags |= DECODE_FLAG_LEVEL1;
+
+ result =
+ _asn1_decode_simple_ber (etype, p, der_len, &out, &out_len,
+ &tmp_len, flags);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ p += tmp_len;
+ DECR_LEN (der_len, tmp_len);
+
+ if (ber_len)
+ *ber_len += tmp_len;
+
+ DECR_LEN (der_len, 2); /* we need the EOC */
+
+ result = append (&total, &total_size, out, out_len);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ free (out);
+ out = NULL;
+
+ if (p[0] == 0 && p[1] == 0) /* EOC */
+ {
+ if (ber_len)
+ *ber_len += 2;
+ break;
+ }
+
+ /* no EOC */
+ der_len += 2;
+
+ if (der_len == 2)
+ {
+ warn ();
+ result = ASN1_DER_ERROR;
+ goto cleanup;
+ }
+ }
+ while (1);
+ }
+ else /* constructed */
+ {
+ long const_len;
+
+ result = asn1_get_length_ber (p, der_len, &len_len);
+ if (result < 0)
+ {
+ warn ();
+ result = ASN1_DER_ERROR;
+ goto cleanup;
+ }
+
+ DECR_LEN (der_len, len_len);
+ p += len_len;
+
+ const_len = result;
+
+ if (ber_len)
+ *ber_len += len_len;
+
+ /* decode the available octet strings */
+ while (const_len > 0)
+ {
+ unsigned tmp_len;
+ unsigned flags = DECODE_FLAG_HAVE_TAG;
+
+ if (dflags & DECODE_FLAG_LEVEL1)
+ flags |= DECODE_FLAG_LEVEL2;
+ else if (dflags & DECODE_FLAG_LEVEL2)
+ flags |= DECODE_FLAG_LEVEL3;
+ else
+ flags |= DECODE_FLAG_LEVEL1;
+
+ result =
+ _asn1_decode_simple_ber (etype, p, der_len, &out, &out_len,
+ &tmp_len, flags);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ p += tmp_len;
+ DECR_LEN (der_len, tmp_len);
+ DECR_LEN (const_len, tmp_len);
+
+ if (ber_len)
+ *ber_len += tmp_len;
+
+ result = append (&total, &total_size, out, out_len);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ free (out);
+ out = NULL;
+ }
+ }
+ }
+ else if (class == ETYPE_CLASS (etype))
+ {
+ if (ber_len)
+ {
+ result = asn1_get_length_der (p, der_len, &len_len);
+ if (result < 0)
+ {
+ warn ();
+ result = ASN1_DER_ERROR;
+ goto cleanup;
+ }
+ *ber_len += result + len_len;
+ }
+
+ /* non-string values are decoded as DER */
+ result =
+ _asn1_decode_simple_der (etype, der, _der_len, &cout, &out_len,
+ dflags);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+
+ result = append (&total, &total_size, cout, out_len);
+ if (result != ASN1_SUCCESS)
+ {
+ warn ();
+ goto cleanup;
+ }
+ }
+ else
+ {
+ warn ();
+ result = ASN1_DER_ERROR;
+ goto cleanup;
+ }
+
+ *str = total;
+ *str_len = total_size;
+
+ return ASN1_SUCCESS;
+cleanup:
+ free (out);
+ free (total);
+ return result;
+}
+
+/**
+ * asn1_decode_simple_ber:
+ * @etype: The type of the string to be encoded (ASN1_ETYPE_)
+ * @der: the encoded string
+ * @_der_len: the bytes of the encoded string
+ * @str: a pointer to the data
+ * @str_len: the length of the data
+ * @ber_len: the total length occupied by BER (may be %NULL)
+ *
+ * Decodes a BER encoded type. The output is an allocated value
+ * of the data. This decodes BER STRINGS only. Other types are
+ * decoded as DER.
+ *
+ * Returns: %ASN1_SUCCESS if successful or an error value.
+ **/
+int
+asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len, unsigned char **str,
+ unsigned int *str_len, unsigned int *ber_len)
+{
+ return _asn1_decode_simple_ber (etype, der, _der_len, str, str_len, ber_len,
+ DECODE_FLAG_HAVE_TAG);
+}
diff --git a/grub-core/lib/libtasn1/lib/element.c b/grub-core/lib/libtasn1/lib/element.c
new file mode 100644
index 000000000..d4c558e10
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/element.c
@@ -0,0 +1,1109 @@
+/*
+ * Copyright (C) 2000-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*****************************************************/
+/* File: element.c */
+/* Description: Functions with the read and write */
+/* functions. */
+/*****************************************************/
+
+
+#include <int.h>
+#include "parser_aux.h"
+#include <gstr.h>
+#include "structure.h"
+#include "c-ctype.h"
+#include "element.h"
+
+void
+_asn1_hierarchical_name (asn1_node_const node, char *name, int name_size)
+{
+ asn1_node_const p;
+ char tmp_name[64];
+
+ p = node;
+
+ name[0] = 0;
+
+ while (p != NULL)
+ {
+ if (p->name[0] != 0)
+ {
+ _asn1_str_cpy (tmp_name, sizeof (tmp_name), name),
+ _asn1_str_cpy (name, name_size, p->name);
+ _asn1_str_cat (name, name_size, ".");
+ _asn1_str_cat (name, name_size, tmp_name);
+ }
+ p = _asn1_find_up (p);
+ }
+
+ if (name[0] == 0)
+ _asn1_str_cpy (name, name_size, "ROOT");
+}
+
+
+/******************************************************************/
+/* Function : _asn1_convert_integer */
+/* Description: converts an integer from a null terminated string */
+/* to der decoding. The convertion from a null */
+/* terminated string to an integer is made with */
+/* the 'strtol' function. */
+/* Parameters: */
+/* value: null terminated string to convert. */
+/* value_out: convertion result (memory must be already */
+/* allocated). */
+/* value_out_size: number of bytes of value_out. */
+/* len: number of significant byte of value_out. */
+/* Return: ASN1_MEM_ERROR or ASN1_SUCCESS */
+/******************************************************************/
+int
+_asn1_convert_integer (const unsigned char *value, unsigned char *value_out,
+ int value_out_size, int *len)
+{
+ char negative;
+ unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
+ long valtmp;
+ int k, k2;
+
+ valtmp = _asn1_strtol (value, NULL, 10);
+
+ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
+ {
+ val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF;
+ }
+
+ if (val[0] & 0x80)
+ negative = 1;
+ else
+ negative = 0;
+
+ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++)
+ {
+ if (negative && (val[k] != 0xFF))
+ break;
+ else if (!negative && val[k])
+ break;
+ }
+
+ if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80)))
+ k--;
+
+ *len = SIZEOF_UNSIGNED_LONG_INT - k;
+
+ if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size)
+ /* VALUE_OUT is too short to contain the value conversion */
+ return ASN1_MEM_ERROR;
+
+ if (value_out != NULL)
+ {
+ for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++)
+ value_out[k2 - k] = val[k2];
+ }
+
+#if 0
+ printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len);
+ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
+ printf (", vOut[%d]=%d", k, value_out[k]);
+ printf ("\n");
+#endif
+
+ return ASN1_SUCCESS;
+}
+
+/* Appends a new element into the sequence (or set) defined by this
+ * node. The new element will have a name of '?number', where number
+ * is a monotonically increased serial number.
+ *
+ * The last element in the list may be provided in @pcache, to avoid
+ * traversing the list, an expensive operation in long lists.
+ *
+ * On success it returns in @pcache the added element (which is the
+ * tail in the list of added elements).
+ */
+int
+_asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
+{
+ asn1_node p, p2;
+ char temp[LTOSTR_MAX_SIZE + 1];
+ long n;
+
+ if (!node || !(node->down))
+ return ASN1_GENERIC_ERROR;
+
+ p = node->down;
+ while ((type_field (p->type) == ASN1_ETYPE_TAG)
+ || (type_field (p->type) == ASN1_ETYPE_SIZE))
+ p = p->right;
+
+ p2 = _asn1_copy_structure3 (p);
+ if (p2 == NULL)
+ return ASN1_GENERIC_ERROR;
+
+ if (pcache == NULL || pcache->tail == NULL || pcache->head != node)
+ {
+ while (p->right)
+ {
+ p = p->right;
+ }
+ }
+ else
+ {
+ p = pcache->tail;
+ }
+
+ _asn1_set_right (p, p2);
+ if (pcache)
+ {
+ pcache->head = node;
+ pcache->tail = p2;
+ }
+
+ if (p->name[0] == 0)
+ _asn1_str_cpy (temp, sizeof (temp), "?1");
+ else
+ {
+ n = strtol (p->name + 1, NULL, 0);
+ n++;
+ temp[0] = '?';
+ _asn1_ltostr (n, temp + 1);
+ }
+ _asn1_set_name (p2, temp);
+ /* p2->type |= CONST_OPTION; */
+
+ return ASN1_SUCCESS;
+}
+
+
+/**
+ * asn1_write_value:
+ * @node_root: pointer to a structure
+ * @name: the name of the element inside the structure that you want to set.
+ * @ivalue: vector used to specify the value to set. If len is >0,
+ * VALUE must be a two's complement form integer. if len=0 *VALUE
+ * must be a null terminated string with an integer value.
+ * @len: number of bytes of *value to use to set the value:
+ * value[0]..value[len-1] or 0 if value is a null terminated string
+ *
+ * Set the value of one element inside a structure.
+ *
+ * If an element is OPTIONAL and you want to delete it, you must use
+ * the value=NULL and len=0. Using "pkix.asn":
+ *
+ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID",
+ * NULL, 0);
+ *
+ * Description for each type:
+ *
+ * INTEGER: VALUE must contain a two's complement form integer.
+ *
+ * value[0]=0xFF , len=1 -> integer=-1.
+ * value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1.
+ * value[0]=0x01 , len=1 -> integer= 1.
+ * value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1.
+ * value="123" , len=0 -> integer= 123.
+ *
+ * ENUMERATED: As INTEGER (but only with not negative numbers).
+ *
+ * BOOLEAN: VALUE must be the null terminated string "TRUE" or
+ * "FALSE" and LEN != 0.
+ *
+ * value="TRUE" , len=1 -> boolean=TRUE.
+ * value="FALSE" , len=1 -> boolean=FALSE.
+ *
+ * OBJECT IDENTIFIER: VALUE must be a null terminated string with
+ * each number separated by a dot (e.g. "1.2.3.543.1"). LEN != 0.
+ *
+ * value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha.
+ *
+ * UTCTime: VALUE must be a null terminated string in one of these
+ * formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ",
+ * "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'",
+ * "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'". LEN != 0.
+ *
+ * value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998
+ * at 12h 00m Greenwich Mean Time
+ *
+ * GeneralizedTime: VALUE must be in one of this format:
+ * "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ",
+ * "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'",
+ * "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s
+ * indicates the seconds with any precision like "10.1" or "01.02".
+ * LEN != 0
+ *
+ * value="2001010112001.12-0700" , len=1 -> time=Jannuary
+ * 1st, 2001 at 12h 00m 01.12s Pacific Daylight Time
+ *
+ * OCTET STRING: VALUE contains the octet string and LEN is the
+ * number of octets.
+ *
+ * value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
+ * len=3 -> three bytes octet string
+ *
+ * GeneralString: VALUE contains the generalstring and LEN is the
+ * number of octets.
+ *
+ * value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
+ * len=3 -> three bytes generalstring
+ *
+ * BIT STRING: VALUE contains the bit string organized by bytes and
+ * LEN is the number of bits.
+ *
+ * value="$\backslash$xCF" , len=6 -> bit string="110011" (six
+ * bits)
+ *
+ * CHOICE: if NAME indicates a choice type, VALUE must specify one of
+ * the alternatives with a null terminated string. LEN != 0. Using
+ * "pkix.asn"\:
+ *
+ * result=asn1_write_value(cert,
+ * "certificate1.tbsCertificate.subject", "rdnSequence",
+ * 1);
+ *
+ * ANY: VALUE indicates the der encoding of a structure. LEN != 0.
+ *
+ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and
+ * LEN != 0. With this instruction another element is appended in
+ * the sequence. The name of this element will be "?1" if it's the
+ * first one, "?2" for the second and so on.
+ *
+ * Using "pkix.asn"\:
+ *
+ * result=asn1_write_value(cert,
+ * "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1);
+ *
+ * SET OF: the same as SEQUENCE OF. Using "pkix.asn":
+ *
+ * result=asn1_write_value(cert,
+ * "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1);
+ *
+ * Returns: %ASN1_SUCCESS if the value was set,
+ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and
+ * %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format.
+ **/
+int
+asn1_write_value (asn1_node node_root, const char *name,
+ const void *ivalue, int len)
+{
+ asn1_node node, p, p2;
+ unsigned char *temp, *value_temp = NULL, *default_temp = NULL;
+ int len2, k, k2, negative;
+ size_t i;
+ const unsigned char *value = ivalue;
+ unsigned int type;
+
+ node = asn1_find_node (node_root, name);
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0))
+ {
+ asn1_delete_structure (&node);
+ return ASN1_SUCCESS;
+ }
+
+ type = type_field (node->type);
+
+ if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF)
+ && (value == NULL) && (len == 0))
+ {
+ p = node->down;
+ while ((type_field (p->type) == ASN1_ETYPE_TAG)
+ || (type_field (p->type) == ASN1_ETYPE_SIZE))
+ p = p->right;
+
+ while (p->right)
+ asn1_delete_structure (&p->right);
+
+ return ASN1_SUCCESS;
+ }
+
+ /* Don't allow element deletion for other types */
+ if (value == NULL)
+ {
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ switch (type)
+ {
+ case ASN1_ETYPE_BOOLEAN:
+ if (!_asn1_strcmp (value, "TRUE"))
+ {
+ if (node->type & CONST_DEFAULT)
+ {
+ p = node->down;
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+ p = p->right;
+ if (p->type & CONST_TRUE)
+ _asn1_set_value (node, NULL, 0);
+ else
+ _asn1_set_value (node, "T", 1);
+ }
+ else
+ _asn1_set_value (node, "T", 1);
+ }
+ else if (!_asn1_strcmp (value, "FALSE"))
+ {
+ if (node->type & CONST_DEFAULT)
+ {
+ p = node->down;
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+ p = p->right;
+ if (p->type & CONST_FALSE)
+ _asn1_set_value (node, NULL, 0);
+ else
+ _asn1_set_value (node, "F", 1);
+ }
+ else
+ _asn1_set_value (node, "F", 1);
+ }
+ else
+ return ASN1_VALUE_NOT_VALID;
+ break;
+ case ASN1_ETYPE_INTEGER:
+ case ASN1_ETYPE_ENUMERATED:
+ if (len == 0)
+ {
+ if ((c_isdigit (value[0])) || (value[0] == '-'))
+ {
+ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+ if (value_temp == NULL)
+ return ASN1_MEM_ALLOC_ERROR;
+
+ _asn1_convert_integer (value, value_temp,
+ SIZEOF_UNSIGNED_LONG_INT, &len);
+ }
+ else
+ { /* is an identifier like v1 */
+ if (!(node->type & CONST_LIST))
+ return ASN1_VALUE_NOT_VALID;
+ p = node->down;
+ while (p)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
+ {
+ if (!_asn1_strcmp (p->name, value))
+ {
+ value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+ if (value_temp == NULL)
+ return ASN1_MEM_ALLOC_ERROR;
+
+ _asn1_convert_integer (p->value,
+ value_temp,
+ SIZEOF_UNSIGNED_LONG_INT,
+ &len);
+ break;
+ }
+ }
+ p = p->right;
+ }
+ if (p == NULL)
+ return ASN1_VALUE_NOT_VALID;
+ }
+ }
+ else
+ { /* len != 0 */
+ value_temp = malloc (len);
+ if (value_temp == NULL)
+ return ASN1_MEM_ALLOC_ERROR;
+ memcpy (value_temp, value, len);
+ }
+
+ if (value_temp[0] & 0x80)
+ negative = 1;
+ else
+ negative = 0;
+
+ if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED))
+ {
+ free (value_temp);
+ return ASN1_VALUE_NOT_VALID;
+ }
+
+ for (k = 0; k < len - 1; k++)
+ if (negative && (value_temp[k] != 0xFF))
+ break;
+ else if (!negative && value_temp[k])
+ break;
+
+ if ((negative && !(value_temp[k] & 0x80)) ||
+ (!negative && (value_temp[k] & 0x80)))
+ k--;
+
+ _asn1_set_value_lv (node, value_temp + k, len - k);
+
+ if (node->type & CONST_DEFAULT)
+ {
+ p = node->down;
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+ p = p->right;
+ if ((c_isdigit (p->value[0])) || (p->value[0] == '-'))
+ {
+ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+ if (default_temp == NULL)
+ {
+ free (value_temp);
+ return ASN1_MEM_ALLOC_ERROR;
+ }
+
+ _asn1_convert_integer (p->value, default_temp,
+ SIZEOF_UNSIGNED_LONG_INT, &len2);
+ }
+ else
+ { /* is an identifier like v1 */
+ if (!(node->type & CONST_LIST))
+ {
+ free (value_temp);
+ return ASN1_VALUE_NOT_VALID;
+ }
+ p2 = node->down;
+ while (p2)
+ {
+ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
+ {
+ if (!_asn1_strcmp (p2->name, p->value))
+ {
+ default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+ if (default_temp == NULL)
+ {
+ free (value_temp);
+ return ASN1_MEM_ALLOC_ERROR;
+ }
+
+ _asn1_convert_integer (p2->value,
+ default_temp,
+ SIZEOF_UNSIGNED_LONG_INT,
+ &len2);
+ break;
+ }
+ }
+ p2 = p2->right;
+ }
+ if (p2 == NULL)
+ {
+ free (value_temp);
+ return ASN1_VALUE_NOT_VALID;
+ }
+ }
+
+
+ if ((len - k) == len2)
+ {
+ for (k2 = 0; k2 < len2; k2++)
+ if (value_temp[k + k2] != default_temp[k2])
+ {
+ break;
+ }
+ if (k2 == len2)
+ _asn1_set_value (node, NULL, 0);
+ }
+ free (default_temp);
+ }
+ free (value_temp);
+ break;
+ case ASN1_ETYPE_OBJECT_ID:
+ for (i = 0; i < _asn1_strlen (value); i++)
+ if ((!c_isdigit (value[i])) && (value[i] != '.') && (value[i] != '+'))
+ return ASN1_VALUE_NOT_VALID;
+ if (node->type & CONST_DEFAULT)
+ {
+ p = node->down;
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+ p = p->right;
+ if (!_asn1_strcmp (value, p->value))
+ {
+ _asn1_set_value (node, NULL, 0);
+ break;
+ }
+ }
+ _asn1_set_value (node, value, _asn1_strlen (value) + 1);
+ break;
+ case ASN1_ETYPE_UTC_TIME:
+ {
+ len = _asn1_strlen (value);
+ if (len < 11)
+ return ASN1_VALUE_NOT_VALID;
+ for (k = 0; k < 10; k++)
+ if (!c_isdigit (value[k]))
+ return ASN1_VALUE_NOT_VALID;
+ switch (len)
+ {
+ case 11:
+ if (value[10] != 'Z')
+ return ASN1_VALUE_NOT_VALID;
+ break;
+ case 13:
+ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])) ||
+ (value[12] != 'Z'))
+ return ASN1_VALUE_NOT_VALID;
+ break;
+ case 15:
+ if ((value[10] != '+') && (value[10] != '-'))
+ return ASN1_VALUE_NOT_VALID;
+ for (k = 11; k < 15; k++)
+ if (!c_isdigit (value[k]))
+ return ASN1_VALUE_NOT_VALID;
+ break;
+ case 17:
+ if ((!c_isdigit (value[10])) || (!c_isdigit (value[11])))
+ return ASN1_VALUE_NOT_VALID;
+ if ((value[12] != '+') && (value[12] != '-'))
+ return ASN1_VALUE_NOT_VALID;
+ for (k = 13; k < 17; k++)
+ if (!c_isdigit (value[k]))
+ return ASN1_VALUE_NOT_VALID;
+ break;
+ default:
+ return ASN1_VALUE_NOT_FOUND;
+ }
+ _asn1_set_value (node, value, len);
+ }
+ break;
+ case ASN1_ETYPE_GENERALIZED_TIME:
+ len = _asn1_strlen (value);
+ _asn1_set_value (node, value, len);
+ break;
+ case ASN1_ETYPE_OCTET_STRING:
+ case ASN1_ETYPE_GENERALSTRING:
+ case ASN1_ETYPE_NUMERIC_STRING:
+ case ASN1_ETYPE_IA5_STRING:
+ case ASN1_ETYPE_TELETEX_STRING:
+ case ASN1_ETYPE_PRINTABLE_STRING:
+ case ASN1_ETYPE_UNIVERSAL_STRING:
+ case ASN1_ETYPE_BMP_STRING:
+ case ASN1_ETYPE_UTF8_STRING:
+ case ASN1_ETYPE_VISIBLE_STRING:
+ if (len == 0)
+ len = _asn1_strlen (value);
+ _asn1_set_value_lv (node, value, len);
+ break;
+ case ASN1_ETYPE_BIT_STRING:
+ if (len == 0)
+ len = _asn1_strlen (value);
+ asn1_length_der ((len >> 3) + 2, NULL, &len2);
+ temp = malloc ((len >> 3) + 2 + len2);
+ if (temp == NULL)
+ return ASN1_MEM_ALLOC_ERROR;
+
+ asn1_bit_der (value, len, temp, &len2);
+ _asn1_set_value_m (node, temp, len2);
+ temp = NULL;
+ break;
+ case ASN1_ETYPE_CHOICE:
+ p = node->down;
+ while (p)
+ {
+ if (!_asn1_strcmp (p->name, value))
+ {
+ p2 = node->down;
+ while (p2)
+ {
+ if (p2 != p)
+ {
+ asn1_delete_structure (&p2);
+ p2 = node->down;
+ }
+ else
+ p2 = p2->right;
+ }
+ break;
+ }
+ p = p->right;
+ }
+ if (!p)
+ return ASN1_ELEMENT_NOT_FOUND;
+ break;
+ case ASN1_ETYPE_ANY:
+ _asn1_set_value_lv (node, value, len);
+ break;
+ case ASN1_ETYPE_SEQUENCE_OF:
+ case ASN1_ETYPE_SET_OF:
+ if (_asn1_strcmp (value, "NEW"))
+ return ASN1_VALUE_NOT_VALID;
+ _asn1_append_sequence_set (node, NULL);
+ break;
+ default:
+ return ASN1_ELEMENT_NOT_FOUND;
+ break;
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+#define PUT_VALUE( ptr, ptr_size, data, data_size) \
+ *len = data_size; \
+ if (ptr_size < data_size) { \
+ return ASN1_MEM_ERROR; \
+ } else { \
+ if (ptr && data_size > 0) \
+ memcpy (ptr, data, data_size); \
+ }
+
+#define PUT_STR_VALUE( ptr, ptr_size, data) \
+ *len = _asn1_strlen (data) + 1; \
+ if (ptr_size < *len) { \
+ return ASN1_MEM_ERROR; \
+ } else { \
+ /* this strcpy is checked */ \
+ if (ptr) { \
+ _asn1_strcpy (ptr, data); \
+ } \
+ }
+
+#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \
+ *len = data_size + 1; \
+ if (ptr_size < *len) { \
+ return ASN1_MEM_ERROR; \
+ } else { \
+ /* this strcpy is checked */ \
+ if (ptr) { \
+ if (data_size > 0) \
+ memcpy (ptr, data, data_size); \
+ ptr[data_size] = 0; \
+ } \
+ }
+
+#define ADD_STR_VALUE( ptr, ptr_size, data) \
+ *len += _asn1_strlen(data); \
+ if (ptr_size < (int) *len) { \
+ (*len)++; \
+ return ASN1_MEM_ERROR; \
+ } else { \
+ /* this strcat is checked */ \
+ if (ptr) _asn1_strcat (ptr, data); \
+ }
+
+/**
+ * asn1_read_value:
+ * @root: pointer to a structure.
+ * @name: the name of the element inside a structure that you want to read.
+ * @ivalue: vector that will contain the element's content, must be a
+ * pointer to memory cells already allocated (may be %NULL).
+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
+ * holds the sizeof value.
+ *
+ * Returns the value of one element inside a structure.
+ * If an element is OPTIONAL and this returns
+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
+ * in the der encoding that created the structure. The first element
+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
+ * so on. If the @root provided is a node to specific sequence element,
+ * then the keyword "?CURRENT" is also acceptable and indicates the
+ * current sequence element of this node.
+ *
+ * Note that there can be valid values with length zero. In these case
+ * this function will succeed and @len will be zero.
+ *
+ * INTEGER: VALUE will contain a two's complement form integer.
+ *
+ * integer=-1 -> value[0]=0xFF , len=1.
+ * integer=1 -> value[0]=0x01 , len=1.
+ *
+ * ENUMERATED: As INTEGER (but only with not negative numbers).
+ *
+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
+ * "FALSE" and LEN=5 or LEN=6.
+ *
+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
+ * each number separated by a dot (i.e. "1.2.3.543.1").
+ *
+ * LEN = strlen(VALUE)+1
+ *
+ * UTCTime: VALUE will be a null terminated string in one of these
+ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
+ * LEN=strlen(VALUE)+1.
+ *
+ * GeneralizedTime: VALUE will be a null terminated string in the
+ * same format used to set the value.
+ *
+ * OCTET STRING: VALUE will contain the octet string and LEN will be
+ * the number of octets.
+ *
+ * GeneralString: VALUE will contain the generalstring and LEN will
+ * be the number of octets.
+ *
+ * BIT STRING: VALUE will contain the bit string organized by bytes
+ * and LEN will be the number of bits.
+ *
+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
+ * alternative selected.
+ *
+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
+ * encoding of the structure actually used.
+ *
+ * Returns: %ASN1_SUCCESS if value is returned,
+ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
+ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
+ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
+ * to store the result, and in this case @len will contain the number of
+ * bytes needed. On the occasion that the stored data are of zero-length
+ * this function may return %ASN1_SUCCESS even if the provided @len is zero.
+ **/
+int
+asn1_read_value (asn1_node_const root, const char *name, void *ivalue,
+ int *len)
+{
+ return asn1_read_value_type (root, name, ivalue, len, NULL);
+}
+
+/**
+ * asn1_read_value_type:
+ * @root: pointer to a structure.
+ * @name: the name of the element inside a structure that you want to read.
+ * @ivalue: vector that will contain the element's content, must be a
+ * pointer to memory cells already allocated (may be %NULL).
+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
+ * holds the sizeof value.
+ * @etype: The type of the value read (ASN1_ETYPE)
+ *
+ * Returns the type and value of one element inside a structure.
+ * If an element is OPTIONAL and this returns
+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
+ * in the der encoding that created the structure. The first element
+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
+ * so on. If the @root provided is a node to specific sequence element,
+ * then the keyword "?CURRENT" is also acceptable and indicates the
+ * current sequence element of this node.
+ *
+ * Note that there can be valid values with length zero. In these case
+ * this function will succeed and @len will be zero.
+ *
+ *
+ * INTEGER: VALUE will contain a two's complement form integer.
+ *
+ * integer=-1 -> value[0]=0xFF , len=1.
+ * integer=1 -> value[0]=0x01 , len=1.
+ *
+ * ENUMERATED: As INTEGER (but only with not negative numbers).
+ *
+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
+ * "FALSE" and LEN=5 or LEN=6.
+ *
+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
+ * each number separated by a dot (i.e. "1.2.3.543.1").
+ *
+ * LEN = strlen(VALUE)+1
+ *
+ * UTCTime: VALUE will be a null terminated string in one of these
+ * formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
+ * LEN=strlen(VALUE)+1.
+ *
+ * GeneralizedTime: VALUE will be a null terminated string in the
+ * same format used to set the value.
+ *
+ * OCTET STRING: VALUE will contain the octet string and LEN will be
+ * the number of octets.
+ *
+ * GeneralString: VALUE will contain the generalstring and LEN will
+ * be the number of octets.
+ *
+ * BIT STRING: VALUE will contain the bit string organized by bytes
+ * and LEN will be the number of bits.
+ *
+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
+ * alternative selected.
+ *
+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
+ * encoding of the structure actually used.
+ *
+ * Returns: %ASN1_SUCCESS if value is returned,
+ * %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
+ * %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
+ * selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
+ * to store the result, and in this case @len will contain the number of
+ * bytes needed. On the occasion that the stored data are of zero-length
+ * this function may return %ASN1_SUCCESS even if the provided @len is zero.
+ **/
+int
+asn1_read_value_type (asn1_node_const root, const char *name, void *ivalue,
+ int *len, unsigned int *etype)
+{
+ asn1_node_const node, p, p2;
+ int len2, len3, result;
+ int value_size = *len;
+ unsigned char *value = ivalue;
+ unsigned type;
+
+ node = asn1_find_node (root, name);
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ type = type_field (node->type);
+
+ if ((type != ASN1_ETYPE_NULL) &&
+ (type != ASN1_ETYPE_CHOICE) &&
+ !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) &&
+ (node->value == NULL))
+ return ASN1_VALUE_NOT_FOUND;
+
+ if (etype)
+ *etype = type;
+ switch (type)
+ {
+ case ASN1_ETYPE_NULL:
+ PUT_STR_VALUE (value, value_size, "NULL");
+ break;
+ case ASN1_ETYPE_BOOLEAN:
+ if ((node->type & CONST_DEFAULT) && (node->value == NULL))
+ {
+ p = node->down;
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+ p = p->right;
+ if (p->type & CONST_TRUE)
+ {
+ PUT_STR_VALUE (value, value_size, "TRUE");
+ }
+ else
+ {
+ PUT_STR_VALUE (value, value_size, "FALSE");
+ }
+ }
+ else if (node->value[0] == 'T')
+ {
+ PUT_STR_VALUE (value, value_size, "TRUE");
+ }
+ else
+ {
+ PUT_STR_VALUE (value, value_size, "FALSE");
+ }
+ break;
+ case ASN1_ETYPE_INTEGER:
+ case ASN1_ETYPE_ENUMERATED:
+ if ((node->type & CONST_DEFAULT) && (node->value == NULL))
+ {
+ p = node->down;
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+ p = p->right;
+ if ((c_isdigit (p->value[0])) || (p->value[0] == '-')
+ || (p->value[0] == '+'))
+ {
+ result = _asn1_convert_integer
+ (p->value, value, value_size, len);
+ if (result != ASN1_SUCCESS)
+ return result;
+ }
+ else
+ { /* is an identifier like v1 */
+ p2 = node->down;
+ while (p2)
+ {
+ if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
+ {
+ if (!_asn1_strcmp (p2->name, p->value))
+ {
+ result = _asn1_convert_integer
+ (p2->value, value, value_size, len);
+ if (result != ASN1_SUCCESS)
+ return result;
+ break;
+ }
+ }
+ p2 = p2->right;
+ }
+ }
+ }
+ else
+ {
+ len2 = -1;
+ result = asn1_get_octet_der
+ (node->value, node->value_len, &len2, value, value_size, len);
+ if (result != ASN1_SUCCESS)
+ return result;
+ }
+ break;
+ case ASN1_ETYPE_OBJECT_ID:
+ if (node->type & CONST_ASSIGN)
+ {
+ *len = 0;
+ if (value)
+ value[0] = 0;
+ p = node->down;
+ while (p)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
+ {
+ ADD_STR_VALUE (value, value_size, p->value);
+ if (p->right)
+ {
+ ADD_STR_VALUE (value, value_size, ".");
+ }
+ }
+ p = p->right;
+ }
+ (*len)++;
+ }
+ else if ((node->type & CONST_DEFAULT) && (node->value == NULL))
+ {
+ p = node->down;
+ while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+ p = p->right;
+ PUT_STR_VALUE (value, value_size, p->value);
+ }
+ else
+ {
+ PUT_STR_VALUE (value, value_size, node->value);
+ }
+ break;
+ case ASN1_ETYPE_GENERALIZED_TIME:
+ case ASN1_ETYPE_UTC_TIME:
+ PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len);
+ break;
+ case ASN1_ETYPE_OCTET_STRING:
+ case ASN1_ETYPE_GENERALSTRING:
+ case ASN1_ETYPE_NUMERIC_STRING:
+ case ASN1_ETYPE_IA5_STRING:
+ case ASN1_ETYPE_TELETEX_STRING:
+ case ASN1_ETYPE_PRINTABLE_STRING:
+ case ASN1_ETYPE_UNIVERSAL_STRING:
+ case ASN1_ETYPE_BMP_STRING:
+ case ASN1_ETYPE_UTF8_STRING:
+ case ASN1_ETYPE_VISIBLE_STRING:
+ len2 = -1;
+ result = asn1_get_octet_der
+ (node->value, node->value_len, &len2, value, value_size, len);
+ if (result != ASN1_SUCCESS)
+ return result;
+ break;
+ case ASN1_ETYPE_BIT_STRING:
+ len2 = -1;
+ result = asn1_get_bit_der
+ (node->value, node->value_len, &len2, value, value_size, len);
+ if (result != ASN1_SUCCESS)
+ return result;
+ break;
+ case ASN1_ETYPE_CHOICE:
+ PUT_STR_VALUE (value, value_size, node->down->name);
+ break;
+ case ASN1_ETYPE_ANY:
+ len3 = -1;
+ len2 = asn1_get_length_der (node->value, node->value_len, &len3);
+ if (len2 < 0)
+ return ASN1_DER_ERROR;
+ PUT_VALUE (value, value_size, node->value + len3, len2);
+ break;
+ default:
+ return ASN1_ELEMENT_NOT_FOUND;
+ break;
+ }
+ return ASN1_SUCCESS;
+}
+
+
+/**
+ * asn1_read_tag:
+ * @root: pointer to a structure
+ * @name: the name of the element inside a structure.
+ * @tagValue: variable that will contain the TAG value.
+ * @classValue: variable that will specify the TAG type.
+ *
+ * Returns the TAG and the CLASS of one element inside a structure.
+ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION,
+ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or
+ * %ASN1_CLASS_CONTEXT_SPECIFIC.
+ *
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
+ * @name is not a valid element.
+ **/
+int
+asn1_read_tag (asn1_node_const root, const char *name, int *tagValue,
+ int *classValue)
+{
+ asn1_node node, p, pTag;
+
+ node = asn1_find_node (root, name);
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node->down;
+
+ /* pTag will points to the IMPLICIT TAG */
+ pTag = NULL;
+ if (node->type & CONST_TAG)
+ {
+ while (p)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_TAG)
+ {
+ if ((p->type & CONST_IMPLICIT) && (pTag == NULL))
+ pTag = p;
+ else if (p->type & CONST_EXPLICIT)
+ pTag = NULL;
+ }
+ p = p->right;
+ }
+ }
+
+ if (pTag)
+ {
+ *tagValue = _asn1_strtoul (pTag->value, NULL, 10);
+
+ if (pTag->type & CONST_APPLICATION)
+ *classValue = ASN1_CLASS_APPLICATION;
+ else if (pTag->type & CONST_UNIVERSAL)
+ *classValue = ASN1_CLASS_UNIVERSAL;
+ else if (pTag->type & CONST_PRIVATE)
+ *classValue = ASN1_CLASS_PRIVATE;
+ else
+ *classValue = ASN1_CLASS_CONTEXT_SPECIFIC;
+ }
+ else
+ {
+ unsigned type = type_field (node->type);
+ *classValue = ASN1_CLASS_UNIVERSAL;
+
+ switch (type)
+ {
+ CASE_HANDLED_ETYPES:
+ *tagValue = _asn1_tags[type].tag;
+ break;
+ case ASN1_ETYPE_TAG:
+ case ASN1_ETYPE_CHOICE:
+ case ASN1_ETYPE_ANY:
+ *tagValue = -1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ASN1_SUCCESS;
+}
+
+/**
+ * asn1_read_node_value:
+ * @node: pointer to a node.
+ * @data: a point to a asn1_data_node_st
+ *
+ * Returns the value a data node inside a asn1_node structure.
+ * The data returned should be handled as constant values.
+ *
+ * Returns: %ASN1_SUCCESS if the node exists.
+ **/
+int
+asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data)
+{
+ data->name = node->name;
+ data->value = node->value;
+ data->value_len = node->value_len;
+ data->type = type_field (node->type);
+
+ return ASN1_SUCCESS;
+}
diff --git a/grub-core/lib/libtasn1/lib/element.h b/grub-core/lib/libtasn1/lib/element.h
new file mode 100644
index 000000000..8dd0ceba8
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/element.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2000-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef _ELEMENT_H
+# define _ELEMENT_H
+
+
+struct node_tail_cache_st
+{
+ asn1_node head; /* the first element of the sequence */
+ asn1_node tail;
+};
+
+int _asn1_append_sequence_set (asn1_node node,
+ struct node_tail_cache_st *pcached);
+
+int _asn1_convert_integer (const unsigned char *value,
+ unsigned char *value_out,
+ int value_out_size, int *len);
+
+void _asn1_hierarchical_name (asn1_node_const node, char *name,
+ int name_size);
+
+#endif
diff --git a/grub-core/lib/libtasn1/lib/errors.c b/grub-core/lib/libtasn1/lib/errors.c
new file mode 100644
index 000000000..aef5dfe6f
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/errors.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include <int.h>
+#ifdef STDC_HEADERS
+# include <stdarg.h>
+#endif
+
+#define LIBTASN1_ERROR_ENTRY(name) { #name, name }
+
+struct libtasn1_error_entry
+{
+ const char *name;
+ int number;
+};
+typedef struct libtasn1_error_entry libtasn1_error_entry;
+
+static const libtasn1_error_entry error_algorithms[] = {
+ LIBTASN1_ERROR_ENTRY (ASN1_SUCCESS),
+ LIBTASN1_ERROR_ENTRY (ASN1_FILE_NOT_FOUND),
+ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_FOUND),
+ LIBTASN1_ERROR_ENTRY (ASN1_IDENTIFIER_NOT_FOUND),
+ LIBTASN1_ERROR_ENTRY (ASN1_DER_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_FOUND),
+ LIBTASN1_ERROR_ENTRY (ASN1_GENERIC_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_VALUE_NOT_VALID),
+ LIBTASN1_ERROR_ENTRY (ASN1_TAG_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_TAG_IMPLICIT),
+ LIBTASN1_ERROR_ENTRY (ASN1_ERROR_TYPE_ANY),
+ LIBTASN1_ERROR_ENTRY (ASN1_SYNTAX_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_MEM_ALLOC_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_DER_OVERFLOW),
+ LIBTASN1_ERROR_ENTRY (ASN1_NAME_TOO_LONG),
+ LIBTASN1_ERROR_ENTRY (ASN1_ARRAY_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_ELEMENT_NOT_EMPTY),
+ LIBTASN1_ERROR_ENTRY (ASN1_TIME_ENCODING_ERROR),
+ LIBTASN1_ERROR_ENTRY (ASN1_RECURSION),
+ {0, 0}
+};
+
+/**
+ * asn1_perror:
+ * @error: is an error returned by a libtasn1 function.
+ *
+ * Prints a string to stderr with a description of an error. This
+ * function is like perror(). The only difference is that it accepts
+ * an error returned by a libtasn1 function.
+ *
+ * Since: 1.6
+ **/
+void
+asn1_perror (int error)
+{
+ const char *str = asn1_strerror (error);
+ fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
+}
+
+/**
+ * asn1_strerror:
+ * @error: is an error returned by a libtasn1 function.
+ *
+ * Returns a string with a description of an error. This function is
+ * similar to strerror. The only difference is that it accepts an
+ * error (number) returned by a libtasn1 function.
+ *
+ * Returns: Pointer to static zero-terminated string describing error
+ * code.
+ *
+ * Since: 1.6
+ **/
+const char *
+asn1_strerror (int error)
+{
+ const libtasn1_error_entry *p;
+
+ for (p = error_algorithms; p->name != NULL; p++)
+ if (p->number == error)
+ return p->name + sizeof ("ASN1_") - 1;
+
+ return NULL;
+}
diff --git a/grub-core/lib/libtasn1/lib/gstr.c b/grub-core/lib/libtasn1/lib/gstr.c
new file mode 100644
index 000000000..eef419554
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/gstr.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include <int.h>
+#include "gstr.h"
+
+/* These function are like strcat, strcpy. They only
+ * do bounds checking (they shouldn't cause buffer overruns),
+ * and they always produce null terminated strings.
+ *
+ * They should be used only with null terminated strings.
+ */
+void
+_asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
+{
+ size_t str_size = strlen (src);
+ size_t dest_size = strlen (dest);
+
+ if (dest_tot_size - dest_size > str_size)
+ {
+ strcat (dest, src);
+ }
+ else
+ {
+ if (dest_tot_size > dest_size)
+ {
+ strncat (dest, src, (dest_tot_size - dest_size) - 1);
+ dest[dest_tot_size - 1] = 0;
+ }
+ }
+}
+
+/* Returns the bytes copied (not including the null terminator) */
+unsigned int
+_asn1_str_cpy (char *dest, size_t dest_tot_size, const char *src)
+{
+ size_t str_size = strlen (src);
+
+ if (dest_tot_size > str_size)
+ {
+ strcpy (dest, src);
+ return str_size;
+ }
+ else
+ {
+ if (dest_tot_size > 0)
+ {
+ str_size = dest_tot_size - 1;
+ memcpy (dest, src, str_size);
+ dest[str_size] = 0;
+ return str_size;
+ }
+ else
+ return 0;
+ }
+}
diff --git a/grub-core/lib/libtasn1/lib/gstr.h b/grub-core/lib/libtasn1/lib/gstr.h
new file mode 100644
index 000000000..99be6c4af
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/gstr.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef GSTR_H
+# define GSTR_H
+
+unsigned int _asn1_str_cpy (char *dest, size_t dest_tot_size,
+ const char *src);
+void _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src);
+
+# define Estrcpy(x,y) _asn1_str_cpy(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
+# define Estrcat(x,y) _asn1_str_cat(x,ASN1_MAX_ERROR_DESCRIPTION_SIZE,y)
+
+inline static void
+safe_memset (void *data, int c, size_t size)
+{
+ volatile unsigned volatile_zero = 0;
+ volatile char *vdata = (volatile char *) data;
+
+ /* This is based on a nice trick for safe memset,
+ * sent by David Jacobson in the openssl-dev mailing list.
+ */
+
+ if (size > 0)
+ do
+ {
+ memset (data, c, size);
+ }
+ while (vdata[volatile_zero] != c);
+}
+
+#endif /* GSTR_H */
diff --git a/grub-core/lib/libtasn1/lib/int.h b/grub-core/lib/libtasn1/lib/int.h
new file mode 100644
index 000000000..d94d51c8c
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/int.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef INT_H
+# define INT_H
+
+# ifdef HAVE_CONFIG_H
+# include <config.h>
+# endif
+
+# include <string.h>
+# include <stdlib.h>
+# include <stdio.h>
+# include <stdint.h>
+
+# ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+# endif
+
+# include <libtasn1.h>
+
+# define ASN1_SMALL_VALUE_SIZE 16
+
+/* This structure is also in libtasn1.h, but then contains less
+ fields. You cannot make any modifications to these first fields
+ without breaking ABI. */
+struct asn1_node_st
+{
+ /* public fields: */
+ char name[ASN1_MAX_NAME_SIZE + 1]; /* Node name */
+ unsigned int name_hash;
+ unsigned int type; /* Node type */
+ unsigned char *value; /* Node value */
+ int value_len;
+ asn1_node down; /* Pointer to the son node */
+ asn1_node right; /* Pointer to the brother node */
+ asn1_node left; /* Pointer to the next list element */
+ /* private fields: */
+ unsigned char small_value[ASN1_SMALL_VALUE_SIZE]; /* For small values */
+
+ /* values used during decoding/coding */
+ int tmp_ival;
+ unsigned start; /* the start of the DER sequence - if decoded */
+ unsigned end; /* the end of the DER sequence - if decoded */
+};
+
+typedef struct tag_and_class_st
+{
+ unsigned tag;
+ unsigned class;
+ const char *desc;
+} tag_and_class_st;
+
+/* the types that are handled in _asn1_tags */
+# define CASE_HANDLED_ETYPES \
+ case ASN1_ETYPE_NULL: \
+ case ASN1_ETYPE_BOOLEAN: \
+ case ASN1_ETYPE_INTEGER: \
+ case ASN1_ETYPE_ENUMERATED: \
+ case ASN1_ETYPE_OBJECT_ID: \
+ case ASN1_ETYPE_OCTET_STRING: \
+ case ASN1_ETYPE_GENERALSTRING: \
+ case ASN1_ETYPE_NUMERIC_STRING: \
+ case ASN1_ETYPE_IA5_STRING: \
+ case ASN1_ETYPE_TELETEX_STRING: \
+ case ASN1_ETYPE_PRINTABLE_STRING: \
+ case ASN1_ETYPE_UNIVERSAL_STRING: \
+ case ASN1_ETYPE_BMP_STRING: \
+ case ASN1_ETYPE_UTF8_STRING: \
+ case ASN1_ETYPE_VISIBLE_STRING: \
+ case ASN1_ETYPE_BIT_STRING: \
+ case ASN1_ETYPE_SEQUENCE: \
+ case ASN1_ETYPE_SEQUENCE_OF: \
+ case ASN1_ETYPE_SET: \
+ case ASN1_ETYPE_UTC_TIME: \
+ case ASN1_ETYPE_GENERALIZED_TIME: \
+ case ASN1_ETYPE_SET_OF
+
+# define ETYPE_TAG(etype) (_asn1_tags[etype].tag)
+# define ETYPE_CLASS(etype) (_asn1_tags[etype].class)
+# define ETYPE_OK(etype) (((etype) != ASN1_ETYPE_INVALID && \
+ (etype) < _asn1_tags_size && \
+ _asn1_tags[(etype)].desc != NULL)?1:0)
+
+# define ETYPE_IS_STRING(etype) ((etype == ASN1_ETYPE_GENERALSTRING || \
+ etype == ASN1_ETYPE_NUMERIC_STRING || etype == ASN1_ETYPE_IA5_STRING || \
+ etype == ASN1_ETYPE_TELETEX_STRING || etype == ASN1_ETYPE_PRINTABLE_STRING || \
+ etype == ASN1_ETYPE_UNIVERSAL_STRING || etype == ASN1_ETYPE_BMP_STRING || \
+ etype == ASN1_ETYPE_UTF8_STRING || etype == ASN1_ETYPE_VISIBLE_STRING || \
+ etype == ASN1_ETYPE_OCTET_STRING)?1:0)
+
+extern unsigned int _asn1_tags_size;
+extern const tag_and_class_st _asn1_tags[];
+
+# define _asn1_strlen(s) strlen((const char *) s)
+# define _asn1_strtol(n,e,b) strtol((const char *) n, e, b)
+# define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
+# define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
+# define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
+# define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
+
+# if SIZEOF_UNSIGNED_LONG_INT == 8
+# define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
+# else
+# define _asn1_strtou64(n,e,b) strtoull((const char *) n, e, b)
+# endif
+
+# define MAX_LOG_SIZE 1024 /* maximum number of characters of a log message */
+
+/* Define used for visiting trees. */
+# define UP 1
+# define RIGHT 2
+# define DOWN 3
+
+/***********************************************************************/
+/* List of constants to better specify the type of typedef asn1_node_st. */
+/***********************************************************************/
+/* Used with TYPE_TAG */
+# define CONST_UNIVERSAL (1U<<8)
+# define CONST_PRIVATE (1U<<9)
+# define CONST_APPLICATION (1U<<10)
+# define CONST_EXPLICIT (1U<<11)
+# define CONST_IMPLICIT (1U<<12)
+
+# define CONST_TAG (1U<<13) /* Used in ASN.1 assignement */
+# define CONST_OPTION (1U<<14)
+# define CONST_DEFAULT (1U<<15)
+# define CONST_TRUE (1U<<16)
+# define CONST_FALSE (1U<<17)
+
+# define CONST_LIST (1U<<18) /* Used with TYPE_INTEGER and TYPE_BIT_STRING */
+# define CONST_MIN_MAX (1U<<19)
+
+# define CONST_1_PARAM (1U<<20)
+
+# define CONST_SIZE (1U<<21)
+
+# define CONST_DEFINED_BY (1U<<22)
+
+/* Those two are deprecated and used for backwards compatibility */
+# define CONST_GENERALIZED (1U<<23)
+# define CONST_UTC (1U<<24)
+
+/* #define CONST_IMPORTS (1U<<25) */
+
+# define CONST_NOT_USED (1U<<26)
+# define CONST_SET (1U<<27)
+# define CONST_ASSIGN (1U<<28)
+
+# define CONST_DOWN (1U<<29)
+# define CONST_RIGHT (1U<<30)
+
+
+# define ASN1_ETYPE_TIME 17
+/****************************************/
+/* Returns the first 8 bits. */
+/* Used with the field type of asn1_node_st */
+/****************************************/
+inline static unsigned int
+type_field (unsigned int ntype)
+{
+ return (ntype & 0xff);
+}
+
+/* To convert old types from a static structure */
+inline static unsigned int
+convert_old_type (unsigned int ntype)
+{
+ unsigned int type = ntype & 0xff;
+ if (type == ASN1_ETYPE_TIME)
+ {
+ if (ntype & CONST_UTC)
+ type = ASN1_ETYPE_UTC_TIME;
+ else
+ type = ASN1_ETYPE_GENERALIZED_TIME;
+
+ ntype &= ~(CONST_UTC | CONST_GENERALIZED);
+ ntype &= 0xffffff00;
+ ntype |= type;
+
+ return ntype;
+ }
+ else
+ return ntype;
+}
+
+static inline void *
+_asn1_realloc (void *ptr, size_t size)
+{
+ void *ret;
+
+ if (size == 0)
+ return ptr;
+
+ ret = realloc (ptr, size);
+ if (ret == NULL)
+ {
+ free (ptr);
+ }
+ return ret;
+}
+
+#endif /* INT_H */
diff --git a/grub-core/lib/libtasn1/lib/parser_aux.c b/grub-core/lib/libtasn1/lib/parser_aux.c
new file mode 100644
index 000000000..c05bd2339
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/parser_aux.c
@@ -0,0 +1,1178 @@
+/*
+ * Copyright (C) 2000-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#include <limits.h> /* WORD_BIT */
+
+#include "int.h"
+#include "parser_aux.h"
+#include "gstr.h"
+#include "structure.h"
+#include "element.h"
+#include "c-ctype.h"
+
+char _asn1_identifierMissing[ASN1_MAX_NAME_SIZE + 1]; /* identifier name not found */
+
+/* Return a hash of the N bytes of X using the method described by
+ Bruno Haible in https://www.haible.de/bruno/hashfunc.html.
+ Note that while many hash functions reduce their result via modulo
+ to a 0..table_size-1 range, this function does not do that.
+
+ This implementation has been changed from size_t -> unsigned int. */
+
+#ifdef __clang__
+__attribute__((no_sanitize ("integer")))
+#endif
+ _GL_ATTRIBUTE_PURE static unsigned int _asn1_hash_name (const char *x)
+{
+ const unsigned char *s = (unsigned char *) x;
+ unsigned h = 0;
+
+ while (*s)
+ h = (*s++) + ((h << 9) | (h >> (WORD_BIT - 9)));
+
+ return h;
+}
+
+/******************************************************/
+/* Function : _asn1_add_static_node */
+/* Description: creates a new NODE_ASN element and */
+/* puts it in the list pointed by e_list. */
+/* Parameters: */
+/* e_list: of type list_type; must be NULL initially */
+/* type: type of the new element (see ASN1_ETYPE_ */
+/* and CONST_ constants). */
+/* Return: pointer to the new element. */
+/******************************************************/
+asn1_node
+_asn1_add_static_node (list_type ** e_list, unsigned int type)
+{
+ list_type *p;
+ asn1_node punt;
+
+ punt = calloc (1, sizeof (struct asn1_node_st));
+ if (punt == NULL)
+ return NULL;
+
+ p = malloc (sizeof (list_type));
+ if (p == NULL)
+ {
+ free (punt);
+ return NULL;
+ }
+
+ p->node = punt;
+ p->next = *e_list;
+ *e_list = p;
+
+ punt->type = type;
+
+ return punt;
+}
+
+static int
+_asn1_add_static_node2 (list_type ** e_list, asn1_node node)
+{
+ list_type *p;
+
+ p = malloc (sizeof (list_type));
+ if (p == NULL)
+ {
+ return -1;
+ }
+
+ p->node = node;
+ p->next = *e_list;
+ *e_list = p;
+
+ return 0;
+}
+
+/**
+ * asn1_find_node:
+ * @pointer: NODE_ASN element pointer.
+ * @name: null terminated string with the element's name to find.
+ *
+ * Searches for an element called @name starting from @pointer. The
+ * name is composed by different identifiers separated by dots. When
+ * *@pointer has a name, the first identifier must be the name of
+ * *@pointer, otherwise it must be the name of one child of *@pointer.
+ *
+ * Returns: the search result, or %NULL if not found.
+ **/
+asn1_node
+asn1_find_node (asn1_node_const pointer, const char *name)
+{
+ asn1_node_const p;
+ char *n_end, n[ASN1_MAX_NAME_SIZE + 1];
+ const char *n_start;
+ unsigned int nsize;
+ unsigned int nhash;
+
+ if (pointer == NULL)
+ return NULL;
+
+ if (name == NULL)
+ return NULL;
+
+ p = pointer;
+ n_start = name;
+
+ if (name[0] == '?' && name[1] == 'C' && p->name[0] == '?')
+ { /* ?CURRENT */
+ n_start = strchr (n_start, '.');
+ if (n_start)
+ n_start++;
+ }
+ else if (p->name[0] != 0)
+ { /* has *pointer got a name ? */
+ n_end = strchr (n_start, '.'); /* search the first dot */
+ if (n_end)
+ {
+ nsize = n_end - n_start;
+ if (nsize >= sizeof (n))
+ return NULL;
+
+ memcpy (n, n_start, nsize);
+ n[nsize] = 0;
+ n_start = n_end;
+ n_start++;
+
+ nhash = _asn1_hash_name (n);
+ }
+ else
+ {
+ _asn1_str_cpy (n, sizeof (n), n_start);
+ nhash = _asn1_hash_name (n);
+
+ n_start = NULL;
+ }
+
+ while (p)
+ {
+ if (nhash == p->name_hash && (!strcmp (p->name, n)))
+ break;
+ else
+ p = p->right;
+ } /* while */
+
+ if (p == NULL)
+ return NULL;
+ }
+ else
+ { /* *pointer doesn't have a name */
+ if (n_start[0] == 0)
+ return (asn1_node) p;
+ }
+
+ while (n_start)
+ { /* Has the end of NAME been reached? */
+ n_end = strchr (n_start, '.'); /* search the next dot */
+ if (n_end)
+ {
+ nsize = n_end - n_start;
+ if (nsize >= sizeof (n))
+ return NULL;
+
+ memcpy (n, n_start, nsize);
+ n[nsize] = 0;
+ n_start = n_end;
+ n_start++;
+
+ nhash = _asn1_hash_name (n);
+ }
+ else
+ {
+ _asn1_str_cpy (n, sizeof (n), n_start);
+ nhash = _asn1_hash_name (n);
+ n_start = NULL;
+ }
+
+ if (p->down == NULL)
+ return NULL;
+
+ p = p->down;
+ if (p == NULL)
+ return NULL;
+
+ /* The identifier "?LAST" indicates the last element
+ in the right chain. */
+ if (n[0] == '?' && n[1] == 'L') /* ?LAST */
+ {
+ while (p->right)
+ p = p->right;
+ }
+ else
+ { /* no "?LAST" */
+ while (p)
+ {
+ if (p->name_hash == nhash && !strcmp (p->name, n))
+ break;
+ else
+ p = p->right;
+ }
+ }
+ if (p == NULL)
+ return NULL;
+ } /* while */
+
+ return (asn1_node) p;
+}
+
+
+/******************************************************************/
+/* Function : _asn1_set_value */
+/* Description: sets the field VALUE in a NODE_ASN element. The */
+/* previous value (if exist) will be lost */
+/* Parameters: */
+/* node: element pointer. */
+/* value: pointer to the value that you want to set. */
+/* len: character number of value. */
+/* Return: pointer to the NODE_ASN element. */
+/******************************************************************/
+asn1_node
+_asn1_set_value (asn1_node node, const void *value, unsigned int len)
+{
+ if (node == NULL)
+ return node;
+ if (node->value)
+ {
+ if (node->value != node->small_value)
+ free (node->value);
+ node->value = NULL;
+ node->value_len = 0;
+ }
+
+ if (!len)
+ return node;
+
+ if (len < sizeof (node->small_value))
+ {
+ node->value = node->small_value;
+ }
+ else
+ {
+ node->value = malloc (len);
+ if (node->value == NULL)
+ return NULL;
+ }
+ node->value_len = len;
+
+ memcpy (node->value, value, len);
+ return node;
+}
+
+/******************************************************************/
+/* Function : _asn1_set_value_lv */
+/* Description: sets the field VALUE in a NODE_ASN element. The */
+/* previous value (if exist) will be lost. The value */
+/* given is stored as an length-value format (LV */
+/* Parameters: */
+/* node: element pointer. */
+/* value: pointer to the value that you want to set. */
+/* len: character number of value. */
+/* Return: pointer to the NODE_ASN element. */
+/******************************************************************/
+asn1_node
+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len)
+{
+ int len2;
+ void *temp;
+
+ if (node == NULL)
+ return node;
+
+ asn1_length_der (len, NULL, &len2);
+ temp = malloc (len + len2);
+ if (temp == NULL)
+ return NULL;
+
+ asn1_octet_der (value, len, temp, &len2);
+ return _asn1_set_value_m (node, temp, len2);
+}
+
+/* the same as _asn1_set_value except that it sets an already malloc'ed
+ * value.
+ */
+asn1_node
+_asn1_set_value_m (asn1_node node, void *value, unsigned int len)
+{
+ if (node == NULL)
+ return node;
+
+ if (node->value)
+ {
+ if (node->value != node->small_value)
+ free (node->value);
+ node->value = NULL;
+ node->value_len = 0;
+ }
+
+ if (!len)
+ return node;
+
+ node->value = value;
+ node->value_len = len;
+
+ return node;
+}
+
+/******************************************************************/
+/* Function : _asn1_append_value */
+/* Description: appends to the field VALUE in a NODE_ASN element. */
+/* */
+/* Parameters: */
+/* node: element pointer. */
+/* value: pointer to the value that you want to be appended. */
+/* len: character number of value. */
+/* Return: pointer to the NODE_ASN element. */
+/******************************************************************/
+asn1_node
+_asn1_append_value (asn1_node node, const void *value, unsigned int len)
+{
+ if (node == NULL)
+ return node;
+
+ if (node->value == NULL)
+ return _asn1_set_value (node, value, len);
+
+ if (len == 0)
+ return node;
+
+ if (node->value == node->small_value)
+ {
+ /* value is in node */
+ int prev_len = node->value_len;
+ node->value_len += len;
+ node->value = malloc (node->value_len);
+ if (node->value == NULL)
+ {
+ node->value_len = 0;
+ return NULL;
+ }
+
+ if (prev_len > 0)
+ memcpy (node->value, node->small_value, prev_len);
+
+ memcpy (&node->value[prev_len], value, len);
+
+ return node;
+ }
+ else /* if (node->value != NULL && node->value != node->small_value) */
+ {
+ /* value is allocated */
+ int prev_len = node->value_len;
+ node->value_len += len;
+
+ node->value = _asn1_realloc (node->value, node->value_len);
+ if (node->value == NULL)
+ {
+ node->value_len = 0;
+ return NULL;
+ }
+
+ memcpy (&node->value[prev_len], value, len);
+
+ return node;
+ }
+}
+
+/******************************************************************/
+/* Function : _asn1_set_name */
+/* Description: sets the field NAME in a NODE_ASN element. The */
+/* previous value (if exist) will be lost */
+/* Parameters: */
+/* node: element pointer. */
+/* name: a null terminated string with the name that you want */
+/* to set. */
+/* Return: pointer to the NODE_ASN element. */
+/******************************************************************/
+asn1_node
+_asn1_set_name (asn1_node node, const char *name)
+{
+ if (node == NULL)
+ return node;
+
+ _asn1_str_cpy (node->name, sizeof (node->name), name ? name : "");
+ node->name_hash = _asn1_hash_name (node->name);
+
+ return node;
+}
+
+/******************************************************************/
+/* Function : _asn1_cpy_name */
+/* Description: copies the field NAME in a NODE_ASN element. */
+/* Parameters: */
+/* dst: a dest element pointer. */
+/* src: a source element pointer. */
+/* Return: pointer to the NODE_ASN element. */
+/******************************************************************/
+asn1_node
+_asn1_cpy_name (asn1_node dst, asn1_node_const src)
+{
+ if (dst == NULL)
+ return dst;
+
+ if (src == NULL)
+ {
+ dst->name[0] = 0;
+ dst->name_hash = _asn1_hash_name (dst->name);
+ return dst;
+ }
+
+ _asn1_str_cpy (dst->name, sizeof (dst->name), src->name);
+ dst->name_hash = src->name_hash;
+
+ return dst;
+}
+
+/******************************************************************/
+/* Function : _asn1_set_right */
+/* Description: sets the field RIGHT in a NODE_ASN element. */
+/* Parameters: */
+/* node: element pointer. */
+/* right: pointer to a NODE_ASN element that you want be pointed*/
+/* by NODE. */
+/* Return: pointer to *NODE. */
+/******************************************************************/
+asn1_node
+_asn1_set_right (asn1_node node, asn1_node right)
+{
+ if (node == NULL)
+ return node;
+ node->right = right;
+ if (right)
+ right->left = node;
+ return node;
+}
+
+
+/******************************************************************/
+/* Function : _asn1_get_last_right */
+/* Description: return the last element along the right chain. */
+/* Parameters: */
+/* node: starting element pointer. */
+/* Return: pointer to the last element along the right chain. */
+/******************************************************************/
+asn1_node
+_asn1_get_last_right (asn1_node_const node)
+{
+ asn1_node_const p;
+
+ if (node == NULL)
+ return NULL;
+ p = node;
+ while (p->right)
+ p = p->right;
+ return (asn1_node) p;
+}
+
+/******************************************************************/
+/* Function : _asn1_remove_node */
+/* Description: gets free the memory allocated for an NODE_ASN */
+/* element (not the elements pointed by it). */
+/* Parameters: */
+/* node: NODE_ASN element pointer. */
+/* flags: ASN1_DELETE_FLAG_* */
+/******************************************************************/
+void
+_asn1_remove_node (asn1_node node, unsigned int flags)
+{
+ if (node == NULL)
+ return;
+
+ if (node->value != NULL)
+ {
+ if (flags & ASN1_DELETE_FLAG_ZEROIZE)
+ {
+ safe_memset (node->value, 0, node->value_len);
+ }
+
+ if (node->value != node->small_value)
+ free (node->value);
+ }
+ free (node);
+}
+
+/******************************************************************/
+/* Function : _asn1_find_up */
+/* Description: return the father of the NODE_ASN element. */
+/* Parameters: */
+/* node: NODE_ASN element pointer. */
+/* Return: Null if not found. */
+/******************************************************************/
+asn1_node
+_asn1_find_up (asn1_node_const node)
+{
+ asn1_node_const p;
+
+ if (node == NULL)
+ return NULL;
+
+ p = node;
+
+ while ((p->left != NULL) && (p->left->right == p))
+ p = p->left;
+
+ return p->left;
+}
+
+static unsigned
+_asn1_is_up (asn1_node_const up_cand, asn1_node_const down)
+{
+ asn1_node_const d, u;
+
+ if (up_cand == NULL || down == NULL)
+ return 0;
+
+ d = down;
+
+ while ((u = _asn1_find_up (d)) != NULL && u != d)
+ {
+ if (u == up_cand)
+ return 1;
+ d = u;
+ }
+
+ return 0;
+}
+
+/******************************************************************/
+/* Function : _asn1_delete_node_from_list */
+/* Description: deletes the list element given */
+/******************************************************************/
+void
+_asn1_delete_node_from_list (list_type * list, asn1_node node)
+{
+ list_type *p = list;
+
+ while (p)
+ {
+ if (p->node == node)
+ p->node = NULL;
+ p = p->next;
+ }
+}
+
+/******************************************************************/
+/* Function : _asn1_delete_list */
+/* Description: deletes the list elements (not the elements */
+/* pointed by them). */
+/******************************************************************/
+void
+_asn1_delete_list (list_type * e_list)
+{
+ list_type *p;
+
+ while (e_list)
+ {
+ p = e_list;
+ e_list = e_list->next;
+ free (p);
+ }
+}
+
+/******************************************************************/
+/* Function : _asn1_delete_list_and nodes */
+/* Description: deletes the list elements and the elements */
+/* pointed by them. */
+/******************************************************************/
+void
+_asn1_delete_list_and_nodes (list_type * e_list)
+{
+ list_type *p;
+
+ while (e_list)
+ {
+ p = e_list;
+ e_list = e_list->next;
+ _asn1_remove_node (p->node, 0);
+ free (p);
+ }
+}
+
+
+char *
+_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
+{
+ uint64_t d, r;
+ char temp[LTOSTR_MAX_SIZE];
+ int count, k, start;
+ uint64_t val;
+
+ if (v < 0)
+ {
+ str[0] = '-';
+ start = 1;
+ val = -((uint64_t) v);
+ }
+ else
+ {
+ val = v;
+ start = 0;
+ }
+
+ count = 0;
+ do
+ {
+ d = val / 10;
+ r = val - d * 10;
+ temp[start + count] = '0' + (char) r;
+ count++;
+ val = d;
+ }
+ while (val && ((start + count) < LTOSTR_MAX_SIZE - 1));
+
+ for (k = 0; k < count; k++)
+ str[k + start] = temp[start + count - k - 1];
+ str[count + start] = 0;
+ return str;
+}
+
+
+/******************************************************************/
+/* Function : _asn1_change_integer_value */
+/* Description: converts into DER coding the value assign to an */
+/* INTEGER constant. */
+/* Parameters: */
+/* node: root of an ASN1element. */
+/* Return: */
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
+/* otherwise ASN1_SUCCESS */
+/******************************************************************/
+int
+_asn1_change_integer_value (asn1_node node)
+{
+ asn1_node p;
+ unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
+ unsigned char val2[SIZEOF_UNSIGNED_LONG_INT + 1];
+ int len;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node;
+ while (p)
+ {
+ if ((type_field (p->type) == ASN1_ETYPE_INTEGER)
+ && (p->type & CONST_ASSIGN))
+ {
+ if (p->value)
+ {
+ _asn1_convert_integer (p->value, val, sizeof (val), &len);
+ asn1_octet_der (val, len, val2, &len);
+ _asn1_set_value (p, val2, len);
+ }
+ }
+
+ if (p->down)
+ {
+ p = p->down;
+ }
+ else
+ {
+ if (p == node)
+ p = NULL;
+ else if (p->right)
+ p = p->right;
+ else
+ {
+ while (1)
+ {
+ p = _asn1_find_up (p);
+ if (p == node)
+ {
+ p = NULL;
+ break;
+ }
+ if (p && p->right)
+ {
+ p = p->right;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ASN1_SUCCESS;
+}
+
+#define MAX_CONSTANTS 1024
+/******************************************************************/
+/* Function : _asn1_expand_object_id */
+/* Description: expand the IDs of an OBJECT IDENTIFIER constant. */
+/* Parameters: */
+/* list: root of an object list */
+/* node: root of an ASN1 element. */
+/* Return: */
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
+/* otherwise ASN1_SUCCESS */
+/******************************************************************/
+int
+_asn1_expand_object_id (list_type ** list, asn1_node node)
+{
+ asn1_node p, p2, p3, p4, p5;
+ char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1];
+ int move, tlen, tries;
+ unsigned max_constants;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ _asn1_str_cpy (name_root, sizeof (name_root), node->name);
+
+ p = node;
+ move = DOWN;
+ tries = 0;
+
+ while (!((p == node) && (move == UP)))
+ {
+ if (move != UP)
+ {
+ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID)
+ && (p->type & CONST_ASSIGN))
+ {
+ p2 = p->down;
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
+ {
+ if (p2->value && !c_isdigit (p2->value[0]))
+ {
+ _asn1_str_cpy (name2, sizeof (name2), name_root);
+ _asn1_str_cat (name2, sizeof (name2), ".");
+ _asn1_str_cat (name2, sizeof (name2),
+ (char *) p2->value);
+ p3 = asn1_find_node (node, name2);
+ if (!p3 || _asn1_is_up (p2, p3) ||
+ (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID) ||
+ !(p3->type & CONST_ASSIGN))
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ _asn1_set_down (p, p2->right);
+ if (p2->down)
+ _asn1_delete_structure (*list, &p2->down, 0);
+ _asn1_delete_node_from_list (*list, p2);
+ _asn1_remove_node (p2, 0);
+ p2 = p;
+ p4 = p3->down;
+ max_constants = 0;
+ while (p4)
+ {
+ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
+ {
+ max_constants++;
+ if (max_constants == MAX_CONSTANTS)
+ return ASN1_RECURSION;
+
+ p5 =
+ _asn1_add_single_node (ASN1_ETYPE_CONSTANT);
+ _asn1_set_name (p5, p4->name);
+ if (p4->value)
+ {
+ tlen = _asn1_strlen (p4->value);
+ if (tlen > 0)
+ _asn1_set_value (p5, p4->value, tlen + 1);
+ }
+ _asn1_add_static_node2 (list, p5);
+
+ if (p2 == p)
+ {
+ _asn1_set_right (p5, p->down);
+ _asn1_set_down (p, p5);
+ }
+ else
+ {
+ _asn1_set_right (p5, p2->right);
+ _asn1_set_right (p2, p5);
+ }
+ p2 = p5;
+ }
+ p4 = p4->right;
+ }
+ move = DOWN;
+
+ tries++;
+ if (tries >= EXPAND_OBJECT_ID_MAX_RECURSION)
+ return ASN1_RECURSION;
+
+ continue;
+ }
+ }
+ }
+ move = DOWN;
+ }
+ else
+ move = RIGHT;
+
+ tries = 0;
+ if (move == DOWN)
+ {
+ if (p->down)
+ p = p->down;
+ else
+ move = RIGHT;
+ }
+
+ if (p == node)
+ {
+ move = UP;
+ continue;
+ }
+
+ if (move == RIGHT)
+ {
+ if (p && p->right)
+ p = p->right;
+ else
+ move = UP;
+ }
+ if (move == UP)
+ p = _asn1_find_up (p);
+ }
+
+ /*******************************/
+ /* expand DEFAULT */
+ /*******************************/
+ p = node;
+ move = DOWN;
+
+ while (!((p == node) && (move == UP)))
+ {
+ if (move != UP)
+ {
+ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
+ (p->type & CONST_DEFAULT))
+ {
+ p2 = p->down;
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
+ {
+ _asn1_str_cpy (name2, sizeof (name2), name_root);
+ _asn1_str_cat (name2, sizeof (name2), ".");
+ if (p2->value)
+ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
+ p3 = asn1_find_node (node, name2);
+ if (!p3 || (type_field (p3->type) != ASN1_ETYPE_OBJECT_ID)
+ || !(p3->type & CONST_ASSIGN))
+ return ASN1_ELEMENT_NOT_FOUND;
+ p4 = p3->down;
+ name2[0] = 0;
+ while (p4)
+ {
+ if (type_field (p4->type) == ASN1_ETYPE_CONSTANT)
+ {
+ if (p4->value == NULL)
+ return ASN1_VALUE_NOT_FOUND;
+
+ if (name2[0])
+ _asn1_str_cat (name2, sizeof (name2), ".");
+ _asn1_str_cat (name2, sizeof (name2),
+ (char *) p4->value);
+ }
+ p4 = p4->right;
+ }
+ tlen = strlen (name2);
+ if (tlen > 0)
+ _asn1_set_value (p2, name2, tlen + 1);
+ }
+ }
+ move = DOWN;
+ }
+ else
+ move = RIGHT;
+
+ if (move == DOWN)
+ {
+ if (p->down)
+ p = p->down;
+ else
+ move = RIGHT;
+ }
+
+ if (p == node)
+ {
+ move = UP;
+ continue;
+ }
+
+ if (move == RIGHT)
+ {
+ if (p && p->right)
+ p = p->right;
+ else
+ move = UP;
+ }
+ if (move == UP)
+ p = _asn1_find_up (p);
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+/******************************************************************/
+/* Function : _asn1_type_set_config */
+/* Description: sets the CONST_SET and CONST_NOT_USED properties */
+/* in the fields of the SET elements. */
+/* Parameters: */
+/* node: root of an ASN1 element. */
+/* Return: */
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
+/* otherwise ASN1_SUCCESS */
+/******************************************************************/
+int
+_asn1_type_set_config (asn1_node node)
+{
+ asn1_node p, p2;
+ int move;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node;
+ move = DOWN;
+
+ while (!((p == node) && (move == UP)))
+ {
+ if (move != UP)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_SET)
+ {
+ p2 = p->down;
+ while (p2)
+ {
+ if (type_field (p2->type) != ASN1_ETYPE_TAG)
+ p2->type |= CONST_SET | CONST_NOT_USED;
+ p2 = p2->right;
+ }
+ }
+ move = DOWN;
+ }
+ else
+ move = RIGHT;
+
+ if (move == DOWN)
+ {
+ if (p->down)
+ p = p->down;
+ else
+ move = RIGHT;
+ }
+
+ if (p == node)
+ {
+ move = UP;
+ continue;
+ }
+
+ if (move == RIGHT)
+ {
+ if (p && p->right)
+ p = p->right;
+ else
+ move = UP;
+ }
+ if (move == UP)
+ p = _asn1_find_up (p);
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+/******************************************************************/
+/* Function : _asn1_check_identifier */
+/* Description: checks the definitions of all the identifiers */
+/* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */
+/* The _asn1_identifierMissing global variable is filled if */
+/* necessary. */
+/* Parameters: */
+/* node: root of an ASN1 element. */
+/* Return: */
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
+/* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */
+/* otherwise ASN1_SUCCESS */
+/******************************************************************/
+int
+_asn1_check_identifier (asn1_node_const node)
+{
+ asn1_node_const p, p2;
+ char name2[ASN1_MAX_NAME_SIZE * 2 + 2];
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node;
+ while (p)
+ {
+ if (p->value && type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
+ {
+ _asn1_str_cpy (name2, sizeof (name2), node->name);
+ _asn1_str_cat (name2, sizeof (name2), ".");
+ _asn1_str_cat (name2, sizeof (name2), (char *) p->value);
+ p2 = asn1_find_node (node, name2);
+ if (p2 == NULL)
+ {
+ if (p->value)
+ _asn1_str_cpy (_asn1_identifierMissing,
+ sizeof (_asn1_identifierMissing),
+ (char *) p->value);
+ else
+ _asn1_strcpy (_asn1_identifierMissing, "(null)");
+ return ASN1_IDENTIFIER_NOT_FOUND;
+ }
+ }
+ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
+ (p->type & CONST_DEFAULT))
+ {
+ p2 = p->down;
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_DEFAULT))
+ {
+ _asn1_str_cpy (name2, sizeof (name2), node->name);
+ if (p2->value)
+ {
+ _asn1_str_cat (name2, sizeof (name2), ".");
+ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
+ _asn1_str_cpy (_asn1_identifierMissing,
+ sizeof (_asn1_identifierMissing),
+ (char *) p2->value);
+ }
+ else
+ _asn1_strcpy (_asn1_identifierMissing, "(null)");
+
+ p2 = asn1_find_node (node, name2);
+ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID) ||
+ !(p2->type & CONST_ASSIGN))
+ return ASN1_IDENTIFIER_NOT_FOUND;
+ else
+ _asn1_identifierMissing[0] = 0;
+ }
+ }
+ else if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
+ (p->type & CONST_ASSIGN))
+ {
+ p2 = p->down;
+ if (p2 && (type_field (p2->type) == ASN1_ETYPE_CONSTANT))
+ {
+ if (p2->value && !c_isdigit (p2->value[0]))
+ {
+ _asn1_str_cpy (name2, sizeof (name2), node->name);
+ _asn1_str_cat (name2, sizeof (name2), ".");
+ _asn1_str_cat (name2, sizeof (name2), (char *) p2->value);
+ _asn1_str_cpy (_asn1_identifierMissing,
+ sizeof (_asn1_identifierMissing),
+ (char *) p2->value);
+
+ p2 = asn1_find_node (node, name2);
+ if (!p2 || (type_field (p2->type) != ASN1_ETYPE_OBJECT_ID)
+ || !(p2->type & CONST_ASSIGN))
+ return ASN1_IDENTIFIER_NOT_FOUND;
+ else
+ _asn1_identifierMissing[0] = 0;
+ }
+ }
+ }
+
+ if (p->down)
+ {
+ p = p->down;
+ }
+ else if (p->right)
+ p = p->right;
+ else
+ {
+ while (p)
+ {
+ p = _asn1_find_up (p);
+ if (p == node)
+ {
+ p = NULL;
+ break;
+ }
+ if (p && p->right)
+ {
+ p = p->right;
+ break;
+ }
+ }
+ }
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+/******************************************************************/
+/* Function : _asn1_set_default_tag */
+/* Description: sets the default IMPLICIT or EXPLICIT property in */
+/* the tagged elements that don't have this declaration. */
+/* Parameters: */
+/* node: pointer to a DEFINITIONS element. */
+/* Return: */
+/* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */
+/* a DEFINITIONS element, */
+/* otherwise ASN1_SUCCESS */
+/******************************************************************/
+int
+_asn1_set_default_tag (asn1_node node)
+{
+ asn1_node p;
+
+ if ((node == NULL) || (type_field (node->type) != ASN1_ETYPE_DEFINITIONS))
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node;
+ while (p)
+ {
+ if ((type_field (p->type) == ASN1_ETYPE_TAG) &&
+ !(p->type & CONST_EXPLICIT) && !(p->type & CONST_IMPLICIT))
+ {
+ if (node->type & CONST_EXPLICIT)
+ p->type |= CONST_EXPLICIT;
+ else
+ p->type |= CONST_IMPLICIT;
+ }
+
+ if (p->down)
+ {
+ p = p->down;
+ }
+ else if (p->right)
+ p = p->right;
+ else
+ {
+ while (1)
+ {
+ p = _asn1_find_up (p);
+ if (p == node)
+ {
+ p = NULL;
+ break;
+ }
+ if (p && p->right)
+ {
+ p = p->right;
+ break;
+ }
+ }
+ }
+ }
+
+ return ASN1_SUCCESS;
+}
diff --git a/grub-core/lib/libtasn1/lib/parser_aux.h b/grub-core/lib/libtasn1/lib/parser_aux.h
new file mode 100644
index 000000000..3eac1fa30
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/parser_aux.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2000-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#ifndef _PARSER_AUX_H
+# define _PARSER_AUX_H
+
+/***********************************************/
+/* Type: list_type */
+/* Description: type used in the list during */
+/* the structure creation. */
+/***********************************************/
+typedef struct list_struct
+{
+ asn1_node node;
+ struct list_struct *next;
+} list_type;
+
+/***************************************/
+/* Functions used by ASN.1 parser */
+/***************************************/
+asn1_node _asn1_add_static_node (list_type ** e_list, unsigned int type);
+
+void _asn1_delete_list (list_type * e_list);
+
+void _asn1_delete_list_and_nodes (list_type * e_list);
+
+void _asn1_delete_node_from_list (list_type * list, asn1_node node);
+
+asn1_node
+_asn1_set_value (asn1_node node, const void *value, unsigned int len);
+
+asn1_node _asn1_set_value_m (asn1_node node, void *value, unsigned int len);
+
+asn1_node
+_asn1_set_value_lv (asn1_node node, const void *value, unsigned int len);
+
+asn1_node
+_asn1_append_value (asn1_node node, const void *value, unsigned int len);
+
+asn1_node _asn1_set_name (asn1_node node, const char *name);
+
+asn1_node _asn1_cpy_name (asn1_node dst, asn1_node_const src);
+
+asn1_node _asn1_set_right (asn1_node node, asn1_node right);
+
+asn1_node _asn1_get_last_right (asn1_node_const node);
+
+void _asn1_remove_node (asn1_node node, unsigned int flags);
+
+/* Max 64-bit integer length is 20 chars + 1 for sign + 1 for null termination */
+# define LTOSTR_MAX_SIZE 22
+char *_asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE]);
+
+asn1_node _asn1_find_up (asn1_node_const node);
+
+int _asn1_change_integer_value (asn1_node node);
+
+# define EXPAND_OBJECT_ID_MAX_RECURSION 16
+int _asn1_expand_object_id (list_type ** list, asn1_node node);
+
+int _asn1_type_set_config (asn1_node node);
+
+int _asn1_check_identifier (asn1_node_const node);
+
+int _asn1_set_default_tag (asn1_node node);
+
+/******************************************************************/
+/* Function : _asn1_get_right */
+/* Description: returns the element pointed by the RIGHT field of */
+/* a NODE_ASN element. */
+/* Parameters: */
+/* node: NODE_ASN element pointer. */
+/* Return: field RIGHT of NODE. */
+/******************************************************************/
+inline static asn1_node
+_asn1_get_right (asn1_node_const node)
+{
+ if (node == NULL)
+ return NULL;
+ return node->right;
+}
+
+/******************************************************************/
+/* Function : _asn1_set_down */
+/* Description: sets the field DOWN in a NODE_ASN element. */
+/* Parameters: */
+/* node: element pointer. */
+/* down: pointer to a NODE_ASN element that you want be pointed */
+/* by NODE. */
+/* Return: pointer to *NODE. */
+/******************************************************************/
+inline static asn1_node
+_asn1_set_down (asn1_node node, asn1_node down)
+{
+ if (node == NULL)
+ return node;
+ node->down = down;
+ if (down)
+ down->left = node;
+ return node;
+}
+
+/******************************************************************/
+/* Function : _asn1_get_down */
+/* Description: returns the element pointed by the DOWN field of */
+/* a NODE_ASN element. */
+/* Parameters: */
+/* node: NODE_ASN element pointer. */
+/* Return: field DOWN of NODE. */
+/******************************************************************/
+inline static asn1_node
+_asn1_get_down (asn1_node_const node)
+{
+ if (node == NULL)
+ return NULL;
+ return node->down;
+}
+
+/******************************************************************/
+/* Function : _asn1_get_name */
+/* Description: returns the name of a NODE_ASN element. */
+/* Parameters: */
+/* node: NODE_ASN element pointer. */
+/* Return: a null terminated string. */
+/******************************************************************/
+inline static char *
+_asn1_get_name (asn1_node_const node)
+{
+ if (node == NULL)
+ return NULL;
+ return (char *) node->name;
+}
+
+/******************************************************************/
+/* Function : _asn1_mod_type */
+/* Description: change the field TYPE of an NODE_ASN element. */
+/* The new value is the old one | (bitwise or) the */
+/* paramener VALUE. */
+/* Parameters: */
+/* node: NODE_ASN element pointer. */
+/* value: the integer value that must be or-ed with the current */
+/* value of field TYPE. */
+/* Return: NODE pointer. */
+/******************************************************************/
+inline static asn1_node
+_asn1_mod_type (asn1_node node, unsigned int value)
+{
+ if (node == NULL)
+ return node;
+ node->type |= value;
+ return node;
+}
+
+#endif
diff --git a/grub-core/lib/libtasn1/lib/structure.c b/grub-core/lib/libtasn1/lib/structure.c
new file mode 100644
index 000000000..512dd601f
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/structure.c
@@ -0,0 +1,1225 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+
+/*****************************************************/
+/* File: structure.c */
+/* Description: Functions to create and delete an */
+/* ASN1 tree. */
+/*****************************************************/
+
+
+#include <int.h>
+#include <structure.h>
+#include "parser_aux.h"
+#include <gstr.h>
+
+
+extern char _asn1_identifierMissing[];
+
+
+/******************************************************/
+/* Function : _asn1_add_single_node */
+/* Description: creates a new NODE_ASN element. */
+/* Parameters: */
+/* type: type of the new element (see ASN1_ETYPE_ */
+/* and CONST_ constants). */
+/* Return: pointer to the new element. */
+/******************************************************/
+asn1_node
+_asn1_add_single_node (unsigned int type)
+{
+ asn1_node punt;
+
+ punt = calloc (1, sizeof (struct asn1_node_st));
+ if (punt == NULL)
+ return NULL;
+
+ punt->type = type;
+
+ return punt;
+}
+
+
+/******************************************************************/
+/* Function : _asn1_find_left */
+/* Description: returns the NODE_ASN element with RIGHT field that*/
+/* points the element NODE. */
+/* Parameters: */
+/* node: NODE_ASN element pointer. */
+/* Return: NULL if not found. */
+/******************************************************************/
+asn1_node
+_asn1_find_left (asn1_node_const node)
+{
+ if ((node == NULL) || (node->left == NULL) || (node->left->down == node))
+ return NULL;
+
+ return node->left;
+}
+
+
+int
+_asn1_create_static_structure (asn1_node_const pointer,
+ char *output_file_name, char *vector_name)
+{
+ FILE *file;
+ asn1_node_const p;
+ unsigned long t;
+
+ file = fopen (output_file_name, "w");
+
+ if (file == NULL)
+ return ASN1_FILE_NOT_FOUND;
+
+ fprintf (file, "#if HAVE_CONFIG_H\n");
+ fprintf (file, "# include \"config.h\"\n");
+ fprintf (file, "#endif\n\n");
+
+ fprintf (file, "#include <libtasn1.h>\n\n");
+
+ fprintf (file, "const asn1_static_node %s[] = {\n", vector_name);
+
+ p = pointer;
+
+ while (p)
+ {
+ fprintf (file, " { ");
+
+ if (p->name[0] != 0)
+ fprintf (file, "\"%s\", ", p->name);
+ else
+ fprintf (file, "NULL, ");
+
+ t = p->type;
+ if (p->down)
+ t |= CONST_DOWN;
+ if (p->right)
+ t |= CONST_RIGHT;
+
+ fprintf (file, "%lu, ", t);
+
+ if (p->value)
+ fprintf (file, "\"%s\"},\n", p->value);
+ else
+ fprintf (file, "NULL },\n");
+
+ if (p->down)
+ {
+ p = p->down;
+ }
+ else if (p->right)
+ {
+ p = p->right;
+ }
+ else
+ {
+ while (1)
+ {
+ p = _asn1_find_up (p);
+ if (p == pointer)
+ {
+ p = NULL;
+ break;
+ }
+ if (p->right)
+ {
+ p = p->right;
+ break;
+ }
+ }
+ }
+ }
+
+ fprintf (file, " { NULL, 0, NULL }\n};\n");
+
+ fclose (file);
+
+ return ASN1_SUCCESS;
+}
+
+
+/**
+ * asn1_array2tree:
+ * @array: specify the array that contains ASN.1 declarations
+ * @definitions: return the pointer to the structure created by
+ * *ARRAY ASN.1 declarations
+ * @errorDescription: return the error description.
+ *
+ * Creates the structures needed to manage the ASN.1 definitions.
+ * @array is a vector created by asn1_parser2array().
+ *
+ * Returns: %ASN1_SUCCESS if structure was created correctly,
+ * %ASN1_ELEMENT_NOT_EMPTY if *@definitions not NULL,
+ * %ASN1_IDENTIFIER_NOT_FOUND if in the file there is an identifier
+ * that is not defined (see @errorDescription for more information),
+ * %ASN1_ARRAY_ERROR if the array pointed by @array is wrong.
+ **/
+int
+asn1_array2tree (const asn1_static_node * array, asn1_node * definitions,
+ char *errorDescription)
+{
+ asn1_node p, p_last = NULL;
+ unsigned long k;
+ int move;
+ int result;
+ unsigned int type;
+ list_type *e_list = NULL;
+
+ if (errorDescription)
+ errorDescription[0] = 0;
+
+ if (*definitions != NULL)
+ return ASN1_ELEMENT_NOT_EMPTY;
+
+ move = UP;
+
+ for (k = 0; array[k].value || array[k].type || array[k].name; k++)
+ {
+ type = convert_old_type (array[k].type);
+
+ p = _asn1_add_static_node (&e_list, type & (~CONST_DOWN));
+ if (array[k].name)
+ _asn1_set_name (p, array[k].name);
+ if (array[k].value)
+ _asn1_set_value (p, array[k].value, strlen (array[k].value) + 1);
+
+ if (*definitions == NULL)
+ *definitions = p;
+
+ if (move == DOWN)
+ {
+ if (p_last && p_last->down)
+ _asn1_delete_structure (e_list, &p_last->down, 0);
+ _asn1_set_down (p_last, p);
+ }
+ else if (move == RIGHT)
+ {
+ if (p_last && p_last->right)
+ _asn1_delete_structure (e_list, &p_last->right, 0);
+ _asn1_set_right (p_last, p);
+ }
+
+ p_last = p;
+
+ if (type & CONST_DOWN)
+ move = DOWN;
+ else if (type & CONST_RIGHT)
+ move = RIGHT;
+ else
+ {
+ while (p_last != *definitions)
+ {
+ p_last = _asn1_find_up (p_last);
+
+ if (p_last == NULL)
+ break;
+
+ if (p_last->type & CONST_RIGHT)
+ {
+ p_last->type &= ~CONST_RIGHT;
+ move = RIGHT;
+ break;
+ }
+ } /* while */
+ }
+ } /* while */
+
+ if (p_last == *definitions)
+ {
+ result = _asn1_check_identifier (*definitions);
+ if (result == ASN1_SUCCESS)
+ {
+ _asn1_change_integer_value (*definitions);
+ result = _asn1_expand_object_id (&e_list, *definitions);
+ }
+ }
+ else
+ {
+ result = ASN1_ARRAY_ERROR;
+ }
+
+ if (errorDescription != NULL)
+ {
+ if (result == ASN1_IDENTIFIER_NOT_FOUND)
+ {
+ Estrcpy (errorDescription, ":: identifier '");
+ Estrcat (errorDescription, _asn1_identifierMissing);
+ Estrcat (errorDescription, "' not found");
+ }
+ else
+ errorDescription[0] = 0;
+ }
+
+ if (result != ASN1_SUCCESS)
+ {
+ _asn1_delete_list_and_nodes (e_list);
+ *definitions = NULL;
+ }
+ else
+ _asn1_delete_list (e_list);
+
+ return result;
+}
+
+/**
+ * asn1_delete_structure:
+ * @structure: pointer to the structure that you want to delete.
+ *
+ * Deletes the structure *@structure. At the end, *@structure is set
+ * to NULL.
+ *
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
+ * *@structure was NULL.
+ **/
+int
+asn1_delete_structure (asn1_node * structure)
+{
+ return _asn1_delete_structure (NULL, structure, 0);
+}
+
+/**
+ * asn1_delete_structure2:
+ * @structure: pointer to the structure that you want to delete.
+ * @flags: additional flags (see %ASN1_DELETE_FLAG_ZEROIZE)
+ *
+ * Deletes the structure *@structure. At the end, *@structure is set
+ * to NULL.
+ *
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
+ * *@structure was NULL.
+ **/
+int
+asn1_delete_structure2 (asn1_node * structure, unsigned int flags)
+{
+ return _asn1_delete_structure (NULL, structure, flags);
+}
+
+int
+_asn1_delete_structure (list_type * e_list, asn1_node * structure,
+ unsigned int flags)
+{
+ asn1_node p, p2, p3;
+
+ if (*structure == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = *structure;
+ while (p)
+ {
+ if (p->down)
+ {
+ p = p->down;
+ }
+ else
+ { /* no down */
+ p2 = p->right;
+ if (p != *structure)
+ {
+ p3 = _asn1_find_up (p);
+ _asn1_set_down (p3, p2);
+ if (e_list)
+ _asn1_delete_node_from_list (e_list, p);
+ _asn1_remove_node (p, flags);
+ p = p3;
+ }
+ else
+ { /* p==root */
+ p3 = _asn1_find_left (p);
+ if (!p3)
+ {
+ p3 = _asn1_find_up (p);
+ if (p3)
+ _asn1_set_down (p3, p2);
+ else
+ {
+ if (p->right)
+ p->right->left = NULL;
+ }
+ }
+ else
+ _asn1_set_right (p3, p2);
+ if (e_list)
+ _asn1_delete_node_from_list (e_list, p);
+ _asn1_remove_node (p, flags);
+ p = NULL;
+ }
+ }
+ }
+
+ *structure = NULL;
+ return ASN1_SUCCESS;
+}
+
+
+/**
+ * asn1_delete_element:
+ * @structure: pointer to the structure that contains the element you
+ * want to delete.
+ * @element_name: element's name you want to delete.
+ *
+ * Deletes the element named *@element_name inside *@structure.
+ *
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
+ * the @element_name was not found.
+ **/
+int
+asn1_delete_element (asn1_node structure, const char *element_name)
+{
+ asn1_node p2, p3, source_node;
+
+ source_node = asn1_find_node (structure, element_name);
+
+ if (source_node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p2 = source_node->right;
+ p3 = _asn1_find_left (source_node);
+ if (!p3)
+ {
+ p3 = _asn1_find_up (source_node);
+ if (p3)
+ _asn1_set_down (p3, p2);
+ else if (source_node->right)
+ source_node->right->left = NULL;
+ }
+ else
+ _asn1_set_right (p3, p2);
+
+ return asn1_delete_structure (&source_node);
+}
+
+#ifndef __clang_analyzer__
+asn1_node
+_asn1_copy_structure3 (asn1_node_const source_node)
+{
+ asn1_node_const p_s;
+ asn1_node dest_node, p_d, p_d_prev;
+ int move;
+
+ if (source_node == NULL)
+ return NULL;
+
+ dest_node = _asn1_add_single_node (source_node->type);
+ if (dest_node == NULL)
+ return dest_node;
+
+ p_s = source_node;
+ p_d = dest_node;
+
+ move = DOWN;
+
+ do
+ {
+ if (move != UP)
+ {
+ if (p_s->name[0] != 0)
+ _asn1_cpy_name (p_d, p_s);
+ if (p_s->value)
+ _asn1_set_value (p_d, p_s->value, p_s->value_len);
+ if (p_s->down)
+ {
+ p_s = p_s->down;
+ p_d_prev = p_d;
+ p_d = _asn1_add_single_node (p_s->type);
+ _asn1_set_down (p_d_prev, p_d);
+ continue;
+ }
+ p_d->start = p_s->start;
+ p_d->end = p_s->end;
+ }
+
+ if (p_s == source_node)
+ break;
+
+ if (p_s->right)
+ {
+ move = RIGHT;
+ p_s = p_s->right;
+ p_d_prev = p_d;
+ p_d = _asn1_add_single_node (p_s->type);
+ _asn1_set_right (p_d_prev, p_d);
+ }
+ else
+ {
+ move = UP;
+ p_s = _asn1_find_up (p_s);
+ p_d = _asn1_find_up (p_d);
+ }
+ }
+ while (p_s != source_node);
+ return dest_node;
+}
+#else
+
+/* Non-production code */
+asn1_node
+_asn1_copy_structure3 (asn1_node_const source_node)
+{
+ return NULL;
+}
+#endif /* __clang_analyzer__ */
+
+
+static asn1_node
+_asn1_copy_structure2 (asn1_node_const root, const char *source_name)
+{
+ asn1_node source_node;
+
+ source_node = asn1_find_node (root, source_name);
+
+ return _asn1_copy_structure3 (source_node);
+
+}
+
+
+static int
+_asn1_type_choice_config (asn1_node node)
+{
+ asn1_node p, p2, p3, p4;
+ int move, tlen;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node;
+ move = DOWN;
+
+ while (!((p == node) && (move == UP)))
+ {
+ if (move != UP)
+ {
+ if ((type_field (p->type) == ASN1_ETYPE_CHOICE)
+ && (p->type & CONST_TAG))
+ {
+ p2 = p->down;
+ while (p2)
+ {
+ if (type_field (p2->type) != ASN1_ETYPE_TAG)
+ {
+ p2->type |= CONST_TAG;
+ p3 = _asn1_find_left (p2);
+ while (p3)
+ {
+ if (type_field (p3->type) == ASN1_ETYPE_TAG)
+ {
+ p4 = _asn1_add_single_node (p3->type);
+ tlen = _asn1_strlen (p3->value);
+ if (tlen > 0)
+ _asn1_set_value (p4, p3->value, tlen + 1);
+ _asn1_set_right (p4, p2->down);
+ _asn1_set_down (p2, p4);
+ }
+ p3 = _asn1_find_left (p3);
+ }
+ }
+ p2 = p2->right;
+ }
+ p->type &= ~(CONST_TAG);
+ p2 = p->down;
+ while (p2)
+ {
+ p3 = p2->right;
+ if (type_field (p2->type) == ASN1_ETYPE_TAG)
+ asn1_delete_structure (&p2);
+ p2 = p3;
+ }
+ }
+ move = DOWN;
+ }
+ else
+ move = RIGHT;
+
+ if (move == DOWN)
+ {
+ if (p->down)
+ p = p->down;
+ else
+ move = RIGHT;
+ }
+
+ if (p == node)
+ {
+ move = UP;
+ continue;
+ }
+
+ if (move == RIGHT)
+ {
+ if (p->right)
+ p = p->right;
+ else
+ move = UP;
+ }
+ if (move == UP)
+ p = _asn1_find_up (p);
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+static int
+_asn1_expand_identifier (asn1_node * node, asn1_node_const root)
+{
+ asn1_node p, p2, p3;
+ char name2[ASN1_MAX_NAME_SIZE + 2];
+ int move;
+
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = *node;
+ move = DOWN;
+
+ while (!((p == *node) && (move == UP)))
+ {
+ if (move != UP)
+ {
+ if (type_field (p->type) == ASN1_ETYPE_IDENTIFIER)
+ {
+ snprintf (name2, sizeof (name2), "%s.%s", root->name, p->value);
+ p2 = _asn1_copy_structure2 (root, name2);
+ if (p2 == NULL)
+ {
+ return ASN1_IDENTIFIER_NOT_FOUND;
+ }
+ _asn1_cpy_name (p2, p);
+ p2->right = p->right;
+ p2->left = p->left;
+ if (p->right)
+ p->right->left = p2;
+ p3 = p->down;
+ if (p3)
+ {
+ while (p3->right)
+ p3 = p3->right;
+ _asn1_set_right (p3, p2->down);
+ _asn1_set_down (p2, p->down);
+ }
+
+ p3 = _asn1_find_left (p);
+ if (p3)
+ _asn1_set_right (p3, p2);
+ else
+ {
+ p3 = _asn1_find_up (p);
+ if (p3)
+ _asn1_set_down (p3, p2);
+ else
+ {
+ p2->left = NULL;
+ }
+ }
+
+ if (p->type & CONST_SIZE)
+ p2->type |= CONST_SIZE;
+ if (p->type & CONST_TAG)
+ p2->type |= CONST_TAG;
+ if (p->type & CONST_OPTION)
+ p2->type |= CONST_OPTION;
+ if (p->type & CONST_DEFAULT)
+ p2->type |= CONST_DEFAULT;
+ if (p->type & CONST_SET)
+ p2->type |= CONST_SET;
+ if (p->type & CONST_NOT_USED)
+ p2->type |= CONST_NOT_USED;
+
+ if (p == *node)
+ *node = p2;
+ _asn1_remove_node (p, 0);
+ p = p2;
+ move = DOWN;
+ continue;
+ }
+ move = DOWN;
+ }
+ else
+ move = RIGHT;
+
+ if (move == DOWN)
+ {
+ if (p->down)
+ p = p->down;
+ else
+ move = RIGHT;
+ }
+
+ if (p == *node)
+ {
+ move = UP;
+ continue;
+ }
+
+ if (move == RIGHT)
+ {
+ if (p->right)
+ p = p->right;
+ else
+ move = UP;
+ }
+ if (move == UP)
+ p = _asn1_find_up (p);
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+/**
+ * asn1_create_element:
+ * @definitions: pointer to the structure returned by "parser_asn1" function
+ * @source_name: the name of the type of the new structure (must be
+ * inside p_structure).
+ * @element: pointer to the structure created.
+ *
+ * Creates a structure of type @source_name. Example using
+ * "pkix.asn":
+ *
+ * rc = asn1_create_element(cert_def, "PKIX1.Certificate", certptr);
+ *
+ * Returns: %ASN1_SUCCESS if creation OK, %ASN1_ELEMENT_NOT_FOUND if
+ * @source_name is not known.
+ **/
+int
+asn1_create_element (asn1_node_const definitions, const char *source_name,
+ asn1_node * element)
+{
+ asn1_node dest_node;
+ int res;
+
+ dest_node = _asn1_copy_structure2 (definitions, source_name);
+
+ if (dest_node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ _asn1_set_name (dest_node, "");
+
+ res = _asn1_expand_identifier (&dest_node, definitions);
+ _asn1_type_choice_config (dest_node);
+
+ *element = dest_node;
+
+ return res;
+}
+
+
+/**
+ * asn1_print_structure:
+ * @out: pointer to the output file (e.g. stdout).
+ * @structure: pointer to the structure that you want to visit.
+ * @name: an element of the structure
+ * @mode: specify how much of the structure to print, can be
+ * %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE,
+ * %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL.
+ *
+ * Prints on the @out file descriptor the structure's tree starting
+ * from the @name element inside the structure @structure.
+ **/
+void
+asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
+ int mode)
+{
+ asn1_node_const p, root;
+ int k, indent = 0, len, len2, len3;
+
+ if (out == NULL)
+ return;
+
+ root = asn1_find_node (structure, name);
+
+ if (root == NULL)
+ return;
+
+ p = root;
+ while (p)
+ {
+ if (mode == ASN1_PRINT_ALL)
+ {
+ for (k = 0; k < indent; k++)
+ fprintf (out, " ");
+ fprintf (out, "name:");
+ if (p->name[0] != 0)
+ fprintf (out, "%s ", p->name);
+ else
+ fprintf (out, "NULL ");
+ }
+ else
+ {
+ switch (type_field (p->type))
+ {
+ case ASN1_ETYPE_CONSTANT:
+ case ASN1_ETYPE_TAG:
+ case ASN1_ETYPE_SIZE:
+ break;
+ default:
+ for (k = 0; k < indent; k++)
+ fprintf (out, " ");
+ fprintf (out, "name:");
+ if (p->name[0] != 0)
+ fprintf (out, "%s ", p->name);
+ else
+ fprintf (out, "NULL ");
+ }
+ }
+
+ if (mode != ASN1_PRINT_NAME)
+ {
+ unsigned type = type_field (p->type);
+ switch (type)
+ {
+ case ASN1_ETYPE_CONSTANT:
+ if (mode == ASN1_PRINT_ALL)
+ fprintf (out, "type:CONST");
+ break;
+ case ASN1_ETYPE_TAG:
+ if (mode == ASN1_PRINT_ALL)
+ fprintf (out, "type:TAG");
+ break;
+ case ASN1_ETYPE_SIZE:
+ if (mode == ASN1_PRINT_ALL)
+ fprintf (out, "type:SIZE");
+ break;
+ case ASN1_ETYPE_DEFAULT:
+ fprintf (out, "type:DEFAULT");
+ break;
+ case ASN1_ETYPE_IDENTIFIER:
+ fprintf (out, "type:IDENTIFIER");
+ break;
+ case ASN1_ETYPE_ANY:
+ fprintf (out, "type:ANY");
+ break;
+ case ASN1_ETYPE_CHOICE:
+ fprintf (out, "type:CHOICE");
+ break;
+ case ASN1_ETYPE_DEFINITIONS:
+ fprintf (out, "type:DEFINITIONS");
+ break;
+ CASE_HANDLED_ETYPES:
+ fprintf (out, "%s", _asn1_tags[type].desc);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL))
+ {
+ switch (type_field (p->type))
+ {
+ case ASN1_ETYPE_CONSTANT:
+ if (mode == ASN1_PRINT_ALL)
+ if (p->value)
+ fprintf (out, " value:%s", p->value);
+ break;
+ case ASN1_ETYPE_TAG:
+ if (mode == ASN1_PRINT_ALL)
+ if (p->value)
+ fprintf (out, " value:%s", p->value);
+ break;
+ case ASN1_ETYPE_SIZE:
+ if (mode == ASN1_PRINT_ALL)
+ if (p->value)
+ fprintf (out, " value:%s", p->value);
+ break;
+ case ASN1_ETYPE_DEFAULT:
+ if (p->value)
+ fprintf (out, " value:%s", p->value);
+ else if (p->type & CONST_TRUE)
+ fprintf (out, " value:TRUE");
+ else if (p->type & CONST_FALSE)
+ fprintf (out, " value:FALSE");
+ break;
+ case ASN1_ETYPE_IDENTIFIER:
+ if (p->value)
+ fprintf (out, " value:%s", p->value);
+ break;
+ case ASN1_ETYPE_INTEGER:
+ if (p->value)
+ {
+ len2 = -1;
+ len = asn1_get_length_der (p->value, p->value_len, &len2);
+ fprintf (out, " value:0x");
+ if (len > 0)
+ for (k = 0; k < len; k++)
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
+ }
+ break;
+ case ASN1_ETYPE_ENUMERATED:
+ if (p->value)
+ {
+ len2 = -1;
+ len = asn1_get_length_der (p->value, p->value_len, &len2);
+ fprintf (out, " value:0x");
+ if (len > 0)
+ for (k = 0; k < len; k++)
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
+ }
+ break;
+ case ASN1_ETYPE_BOOLEAN:
+ if (p->value)
+ {
+ if (p->value[0] == 'T')
+ fprintf (out, " value:TRUE");
+ else if (p->value[0] == 'F')
+ fprintf (out, " value:FALSE");
+ }
+ break;
+ case ASN1_ETYPE_BIT_STRING:
+ if (p->value)
+ {
+ len2 = -1;
+ len = asn1_get_length_der (p->value, p->value_len, &len2);
+ if (len > 0)
+ {
+ fprintf (out, " value(%i):",
+ (len - 1) * 8 - (p->value[len2]));
+ for (k = 1; k < len; k++)
+ fprintf (out, "%02x",
+ (unsigned) (p->value)[k + len2]);
+ }
+ }
+ break;
+ case ASN1_ETYPE_GENERALIZED_TIME:
+ case ASN1_ETYPE_UTC_TIME:
+ if (p->value)
+ {
+ fprintf (out, " value:");
+ for (k = 0; k < p->value_len; k++)
+ fprintf (out, "%c", (p->value)[k]);
+ }
+ break;
+ case ASN1_ETYPE_GENERALSTRING:
+ case ASN1_ETYPE_NUMERIC_STRING:
+ case ASN1_ETYPE_IA5_STRING:
+ case ASN1_ETYPE_TELETEX_STRING:
+ case ASN1_ETYPE_PRINTABLE_STRING:
+ case ASN1_ETYPE_UNIVERSAL_STRING:
+ case ASN1_ETYPE_UTF8_STRING:
+ case ASN1_ETYPE_VISIBLE_STRING:
+ if (p->value)
+ {
+ len2 = -1;
+ len = asn1_get_length_der (p->value, p->value_len, &len2);
+ fprintf (out, " value:");
+ if (len > 0)
+ for (k = 0; k < len; k++)
+ fprintf (out, "%c", (p->value)[k + len2]);
+ }
+ break;
+ case ASN1_ETYPE_BMP_STRING:
+ case ASN1_ETYPE_OCTET_STRING:
+ if (p->value)
+ {
+ len2 = -1;
+ len = asn1_get_length_der (p->value, p->value_len, &len2);
+ fprintf (out, " value:");
+ if (len > 0)
+ for (k = 0; k < len; k++)
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len2]);
+ }
+ break;
+ case ASN1_ETYPE_OBJECT_ID:
+ if (p->value)
+ fprintf (out, " value:%s", p->value);
+ break;
+ case ASN1_ETYPE_ANY:
+ if (p->value)
+ {
+ len3 = -1;
+ len2 = asn1_get_length_der (p->value, p->value_len, &len3);
+ fprintf (out, " value:");
+ if (len2 > 0)
+ for (k = 0; k < len2; k++)
+ fprintf (out, "%02x", (unsigned) (p->value)[k + len3]);
+ }
+ break;
+ case ASN1_ETYPE_SET:
+ case ASN1_ETYPE_SET_OF:
+ case ASN1_ETYPE_CHOICE:
+ case ASN1_ETYPE_DEFINITIONS:
+ case ASN1_ETYPE_SEQUENCE_OF:
+ case ASN1_ETYPE_SEQUENCE:
+ case ASN1_ETYPE_NULL:
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (mode == ASN1_PRINT_ALL)
+ {
+ if (p->type & 0x1FFFFF00)
+ {
+ fprintf (out, " attr:");
+ if (p->type & CONST_UNIVERSAL)
+ fprintf (out, "UNIVERSAL,");
+ if (p->type & CONST_PRIVATE)
+ fprintf (out, "PRIVATE,");
+ if (p->type & CONST_APPLICATION)
+ fprintf (out, "APPLICATION,");
+ if (p->type & CONST_EXPLICIT)
+ fprintf (out, "EXPLICIT,");
+ if (p->type & CONST_IMPLICIT)
+ fprintf (out, "IMPLICIT,");
+ if (p->type & CONST_TAG)
+ fprintf (out, "TAG,");
+ if (p->type & CONST_DEFAULT)
+ fprintf (out, "DEFAULT,");
+ if (p->type & CONST_TRUE)
+ fprintf (out, "TRUE,");
+ if (p->type & CONST_FALSE)
+ fprintf (out, "FALSE,");
+ if (p->type & CONST_LIST)
+ fprintf (out, "LIST,");
+ if (p->type & CONST_MIN_MAX)
+ fprintf (out, "MIN_MAX,");
+ if (p->type & CONST_OPTION)
+ fprintf (out, "OPTION,");
+ if (p->type & CONST_1_PARAM)
+ fprintf (out, "1_PARAM,");
+ if (p->type & CONST_SIZE)
+ fprintf (out, "SIZE,");
+ if (p->type & CONST_DEFINED_BY)
+ fprintf (out, "DEF_BY,");
+ if (p->type & CONST_GENERALIZED)
+ fprintf (out, "GENERALIZED,");
+ if (p->type & CONST_UTC)
+ fprintf (out, "UTC,");
+ if (p->type & CONST_SET)
+ fprintf (out, "SET,");
+ if (p->type & CONST_NOT_USED)
+ fprintf (out, "NOT_USED,");
+ if (p->type & CONST_ASSIGN)
+ fprintf (out, "ASSIGNMENT,");
+ }
+ }
+
+ if (mode == ASN1_PRINT_ALL)
+ {
+ fprintf (out, "\n");
+ }
+ else
+ {
+ switch (type_field (p->type))
+ {
+ case ASN1_ETYPE_CONSTANT:
+ case ASN1_ETYPE_TAG:
+ case ASN1_ETYPE_SIZE:
+ break;
+ default:
+ fprintf (out, "\n");
+ }
+ }
+
+ if (p->down)
+ {
+ p = p->down;
+ indent += 2;
+ }
+ else if (p == root)
+ {
+ p = NULL;
+ break;
+ }
+ else if (p->right)
+ p = p->right;
+ else
+ {
+ while (1)
+ {
+ p = _asn1_find_up (p);
+ if (p == root)
+ {
+ p = NULL;
+ break;
+ }
+ indent -= 2;
+ if (p->right)
+ {
+ p = p->right;
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+
+/**
+ * asn1_number_of_elements:
+ * @element: pointer to the root of an ASN1 structure.
+ * @name: the name of a sub-structure of ROOT.
+ * @num: pointer to an integer where the result will be stored
+ *
+ * Counts the number of elements of a sub-structure called NAME with
+ * names equal to "?1","?2", ...
+ *
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
+ * @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL.
+ **/
+int
+asn1_number_of_elements (asn1_node_const element, const char *name, int *num)
+{
+ asn1_node_const node, p;
+
+ if (num == NULL)
+ return ASN1_GENERIC_ERROR;
+
+ *num = 0;
+
+ node = asn1_find_node (element, name);
+ if (node == NULL)
+ return ASN1_ELEMENT_NOT_FOUND;
+
+ p = node->down;
+
+ while (p)
+ {
+ if (p->name[0] == '?')
+ (*num)++;
+ p = p->right;
+ }
+
+ return ASN1_SUCCESS;
+}
+
+
+/**
+ * asn1_find_structure_from_oid:
+ * @definitions: ASN1 definitions
+ * @oidValue: value of the OID to search (e.g. "1.2.3.4").
+ *
+ * Search the structure that is defined just after an OID definition.
+ *
+ * Returns: %NULL when @oidValue not found, otherwise the pointer to a
+ * constant string that contains the element name defined just after
+ * the OID.
+ **/
+const char *
+asn1_find_structure_from_oid (asn1_node_const definitions,
+ const char *oidValue)
+{
+ char name[2 * ASN1_MAX_NAME_SIZE + 2];
+ char value[ASN1_MAX_NAME_SIZE];
+ asn1_node p;
+ int len;
+ int result;
+ const char *definitionsName;
+
+ if ((definitions == NULL) || (oidValue == NULL))
+ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */
+
+ definitionsName = definitions->name;
+
+ /* search the OBJECT_ID into definitions */
+ p = definitions->down;
+ while (p)
+ {
+ if ((type_field (p->type) == ASN1_ETYPE_OBJECT_ID) &&
+ (p->type & CONST_ASSIGN))
+ {
+ snprintf (name, sizeof (name), "%s.%s", definitionsName, p->name);
+
+ len = ASN1_MAX_NAME_SIZE;
+ result = asn1_read_value (definitions, name, value, &len);
+
+ if ((result == ASN1_SUCCESS) && (!strcmp (oidValue, value)))
+ {
+ p = p->right;
+ if (p == NULL) /* reach the end of ASN1 definitions */
+ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */
+
+ return p->name;
+ }
+ }
+ p = p->right;
+ }
+
+ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */
+}
+
+/**
+ * asn1_copy_node:
+ * @dst: Destination asn1 node.
+ * @dst_name: Field name in destination node.
+ * @src: Source asn1 node.
+ * @src_name: Field name in source node.
+ *
+ * Create a deep copy of a asn1_node variable. That
+ * function requires @dst to be expanded using asn1_create_element().
+ *
+ * Returns: Return %ASN1_SUCCESS on success.
+ **/
+int
+asn1_copy_node (asn1_node dst, const char *dst_name,
+ asn1_node_const src, const char *src_name)
+{
+ int result;
+ asn1_node dst_node;
+ void *data = NULL;
+ int size = 0;
+
+ result = asn1_der_coding (src, src_name, NULL, &size, NULL);
+ if (result != ASN1_MEM_ERROR)
+ return result;
+
+ data = malloc (size);
+ if (data == NULL)
+ return ASN1_MEM_ERROR;
+
+ result = asn1_der_coding (src, src_name, data, &size, NULL);
+ if (result != ASN1_SUCCESS)
+ {
+ free (data);
+ return result;
+ }
+
+ dst_node = asn1_find_node (dst, dst_name);
+ if (dst_node == NULL)
+ {
+ free (data);
+ return ASN1_ELEMENT_NOT_FOUND;
+ }
+
+ result = asn1_der_decoding (&dst_node, data, size, NULL);
+
+ free (data);
+
+ return result;
+}
+
+/**
+ * asn1_dup_node:
+ * @src: Source asn1 node.
+ * @src_name: Field name in source node.
+ *
+ * Create a deep copy of a asn1_node variable. This function
+ * will return an exact copy of the provided structure.
+ *
+ * Returns: Return %NULL on failure.
+ **/
+asn1_node
+asn1_dup_node (asn1_node_const src, const char *src_name)
+{
+ return _asn1_copy_structure2 (src, src_name);
+}
diff --git a/grub-core/lib/libtasn1/lib/structure.h b/grub-core/lib/libtasn1/lib/structure.h
new file mode 100644
index 000000000..b973ce963
--- /dev/null
+++ b/grub-core/lib/libtasn1/lib/structure.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+/*************************************************/
+/* File: structure.h */
+/* Description: list of exported object by */
+/* "structure.c" */
+/*************************************************/
+
+#ifndef _STRUCTURE_H
+# define _STRUCTURE_H
+
+# include "parser_aux.h" /* list_type */
+
+int _asn1_create_static_structure (asn1_node_const pointer,
+ char *output_file_name, char *vector_name);
+
+asn1_node _asn1_copy_structure3 (asn1_node_const source_node);
+
+asn1_node _asn1_add_single_node (unsigned int type);
+
+asn1_node _asn1_find_left (asn1_node_const node);
+
+int
+_asn1_delete_structure (list_type * e_list, asn1_node * structure,
+ unsigned int flags);
+
+#endif
diff --git a/grub-core/lib/libtasn1/libtasn1.h b/grub-core/lib/libtasn1/libtasn1.h
new file mode 100644
index 000000000..51cc7879f
--- /dev/null
+++ b/grub-core/lib/libtasn1/libtasn1.h
@@ -0,0 +1,643 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * LIBTASN1 is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * LIBTASN1 is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with LIBTASN1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+/**
+ * SECTION:libtasn1
+ * @short_description: GNU ASN.1 library
+ *
+ * The Libtasn1 library provides Abstract Syntax Notation One (ASN.1, as
+ * specified by the X.680 ITU-T recommendation) parsing and structures
+ * management, and Distinguished Encoding Rules (DER, as per X.690)
+ * encoding and decoding functions.
+ */
+
+
+#ifndef LIBTASN1_H
+# define LIBTASN1_H
+
+# ifndef ASN1_API
+# if defined ASN1_BUILDING && defined HAVE_VISIBILITY && HAVE_VISIBILITY
+# define ASN1_API __attribute__((__visibility__("default")))
+# elif defined ASN1_BUILDING && defined _MSC_VER && ! defined ASN1_STATIC
+# define ASN1_API __declspec(dllexport)
+# elif defined _MSC_VER && ! defined ASN1_STATIC
+# define ASN1_API __declspec(dllimport)
+# else
+# define ASN1_API
+# endif
+# endif
+
+# ifdef __GNUC__
+# define __LIBTASN1_CONST__ __attribute__((const))
+# define __LIBTASN1_PURE__ __attribute__((pure))
+# else
+# define __LIBTASN1_CONST__
+# define __LIBTASN1_PURE__
+# endif
+
+# include <sys/types.h>
+# include <time.h>
+# include <stdio.h> /* for FILE* */
+
+# ifdef __cplusplus
+extern "C"
+{
+# endif
+
+/**
+ * ASN1_VERSION:
+ *
+ * Version of the library as a string.
+ */
+# define ASN1_VERSION "4.19.0"
+
+/**
+ * ASN1_VERSION_MAJOR:
+ *
+ * Major version number of the library.
+ */
+# define ASN1_VERSION_MAJOR 4
+
+/**
+ * ASN1_VERSION_MINOR:
+ *
+ * Minor version number of the library.
+ */
+# define ASN1_VERSION_MINOR 19
+
+/**
+ * ASN1_VERSION_PATCH:
+ *
+ * Patch version number of the library.
+ */
+# define ASN1_VERSION_PATCH 0
+
+/**
+ * ASN1_VERSION_NUMBER:
+ *
+ * Version number of the library as a number.
+ */
+# define ASN1_VERSION_NUMBER 0x041300
+
+
+# if defined __GNUC__ && !defined ASN1_INTERNAL_BUILD
+# define _ASN1_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+# if _ASN1_GCC_VERSION >= 30100
+# define _ASN1_GCC_ATTR_DEPRECATED __attribute__ ((__deprecated__))
+# endif
+# endif
+
+# ifndef _ASN1_GCC_ATTR_DEPRECATED
+# define _ASN1_GCC_ATTR_DEPRECATED
+# endif
+
+/*****************************************/
+/* Errors returned by libtasn1 functions */
+/*****************************************/
+# define ASN1_SUCCESS 0
+# define ASN1_FILE_NOT_FOUND 1
+# define ASN1_ELEMENT_NOT_FOUND 2
+# define ASN1_IDENTIFIER_NOT_FOUND 3
+# define ASN1_DER_ERROR 4
+# define ASN1_VALUE_NOT_FOUND 5
+# define ASN1_GENERIC_ERROR 6
+# define ASN1_VALUE_NOT_VALID 7
+# define ASN1_TAG_ERROR 8
+# define ASN1_TAG_IMPLICIT 9
+# define ASN1_ERROR_TYPE_ANY 10
+# define ASN1_SYNTAX_ERROR 11
+# define ASN1_MEM_ERROR 12
+# define ASN1_MEM_ALLOC_ERROR 13
+# define ASN1_DER_OVERFLOW 14
+# define ASN1_NAME_TOO_LONG 15
+# define ASN1_ARRAY_ERROR 16
+# define ASN1_ELEMENT_NOT_EMPTY 17
+# define ASN1_TIME_ENCODING_ERROR 18
+# define ASN1_RECURSION 19
+
+/*************************************/
+/* Constants used in asn1_visit_tree */
+/*************************************/
+# define ASN1_PRINT_NAME 1
+# define ASN1_PRINT_NAME_TYPE 2
+# define ASN1_PRINT_NAME_TYPE_VALUE 3
+# define ASN1_PRINT_ALL 4
+
+/*****************************************/
+/* Constants returned by asn1_read_tag */
+/*****************************************/
+# define ASN1_CLASS_UNIVERSAL 0x00 /* old: 1 */
+# define ASN1_CLASS_APPLICATION 0x40 /* old: 2 */
+# define ASN1_CLASS_CONTEXT_SPECIFIC 0x80 /* old: 3 */
+# define ASN1_CLASS_PRIVATE 0xC0 /* old: 4 */
+# define ASN1_CLASS_STRUCTURED 0x20
+
+/*****************************************/
+/* Constants returned by asn1_read_tag */
+/*****************************************/
+# define ASN1_TAG_BOOLEAN 0x01
+# define ASN1_TAG_INTEGER 0x02
+# define ASN1_TAG_SEQUENCE 0x10
+# define ASN1_TAG_SET 0x11
+# define ASN1_TAG_OCTET_STRING 0x04
+# define ASN1_TAG_BIT_STRING 0x03
+# define ASN1_TAG_UTCTime 0x17
+# define ASN1_TAG_GENERALIZEDTime 0x18
+# define ASN1_TAG_OBJECT_ID 0x06
+# define ASN1_TAG_ENUMERATED 0x0A
+# define ASN1_TAG_NULL 0x05
+# define ASN1_TAG_GENERALSTRING 0x1B
+# define ASN1_TAG_NUMERIC_STRING 0x12
+# define ASN1_TAG_IA5_STRING 0x16
+# define ASN1_TAG_TELETEX_STRING 0x14
+# define ASN1_TAG_PRINTABLE_STRING 0x13
+# define ASN1_TAG_UNIVERSAL_STRING 0x1C
+# define ASN1_TAG_BMP_STRING 0x1E
+# define ASN1_TAG_UTF8_STRING 0x0C
+# define ASN1_TAG_VISIBLE_STRING 0x1A
+
+/**
+ * asn1_node:
+ *
+ * Structure definition used for the node of the tree
+ * that represents an ASN.1 DEFINITION.
+ */
+ typedef struct asn1_node_st asn1_node_st;
+
+ typedef asn1_node_st *asn1_node;
+ typedef const asn1_node_st *asn1_node_const;
+
+/**
+ * ASN1_MAX_NAME_SIZE:
+ *
+ * Maximum number of characters of a name
+ * inside a file with ASN1 definitions.
+ */
+# define ASN1_MAX_NAME_SIZE 64
+
+
+/**
+ * asn1_static_node:
+ * @name: Node name
+ * @type: Node typ
+ * @value: Node value
+ *
+ * For the on-disk format of ASN.1 trees, created by asn1_parser2array().
+ */
+ typedef struct asn1_static_node_st
+ {
+ const char *name; /* Node name */
+ unsigned int type; /* Node type */
+ const void *value; /* Node value */
+ } asn1_static_node;
+
+/* List of constants for field type of asn1_static_node */
+# define ASN1_ETYPE_INVALID 0
+# define ASN1_ETYPE_CONSTANT 1
+# define ASN1_ETYPE_IDENTIFIER 2
+# define ASN1_ETYPE_INTEGER 3
+# define ASN1_ETYPE_BOOLEAN 4
+# define ASN1_ETYPE_SEQUENCE 5
+# define ASN1_ETYPE_BIT_STRING 6
+# define ASN1_ETYPE_OCTET_STRING 7
+# define ASN1_ETYPE_TAG 8
+# define ASN1_ETYPE_DEFAULT 9
+# define ASN1_ETYPE_SIZE 10
+# define ASN1_ETYPE_SEQUENCE_OF 11
+# define ASN1_ETYPE_OBJECT_ID 12
+# define ASN1_ETYPE_ANY 13
+# define ASN1_ETYPE_SET 14
+# define ASN1_ETYPE_SET_OF 15
+# define ASN1_ETYPE_DEFINITIONS 16
+# define ASN1_ETYPE_CHOICE 18
+# define ASN1_ETYPE_IMPORTS 19
+# define ASN1_ETYPE_NULL 20
+# define ASN1_ETYPE_ENUMERATED 21
+# define ASN1_ETYPE_GENERALSTRING 27
+# define ASN1_ETYPE_NUMERIC_STRING 28
+# define ASN1_ETYPE_IA5_STRING 29
+# define ASN1_ETYPE_TELETEX_STRING 30
+# define ASN1_ETYPE_PRINTABLE_STRING 31
+# define ASN1_ETYPE_UNIVERSAL_STRING 32
+# define ASN1_ETYPE_BMP_STRING 33
+# define ASN1_ETYPE_UTF8_STRING 34
+# define ASN1_ETYPE_VISIBLE_STRING 35
+# define ASN1_ETYPE_UTC_TIME 36
+# define ASN1_ETYPE_GENERALIZED_TIME 37
+
+/**
+ * ASN1_DELETE_FLAG_ZEROIZE:
+ *
+ * Used by: asn1_delete_structure2()
+ *
+ * Zeroize values prior to deinitialization.
+ */
+# define ASN1_DELETE_FLAG_ZEROIZE 1
+
+/**
+ * ASN1_DECODE_FLAG_ALLOW_PADDING:
+ *
+ * Used by: asn1_der_decoding2()
+ *
+ * This flag would allow arbitrary data past the DER data.
+ */
+# define ASN1_DECODE_FLAG_ALLOW_PADDING 1
+/**
+ * ASN1_DECODE_FLAG_STRICT_DER:
+ *
+ * Used by: asn1_der_decoding2()
+ *
+ * This flag would ensure that no BER decoding takes place.
+ */
+# define ASN1_DECODE_FLAG_STRICT_DER (1<<1)
+/**
+ * ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME:
+ *
+ * Used by: asn1_der_decoding2()
+ *
+ * This flag will tolerate Time encoding errors when in strict DER.
+ */
+# define ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME (1<<2)
+
+ /* *INDENT-OFF* */
+
+/**
+ * asn1_data_node_st:
+ * @name: Node name
+ * @value: Node value
+ * @value_len: Node value size
+ * @type: Node value type (ASN1_ETYPE_*)
+ *
+ * Data node inside a #asn1_node structure.
+ */
+ struct asn1_data_node_st
+ {
+ const char *name; /* Node name */
+ const void *value; /* Node value */
+ unsigned int value_len; /* Node value size */
+ unsigned int type; /* Node value type (ASN1_ETYPE_*) */
+};
+
+ /* *INDENT-ON* */
+
+ typedef struct asn1_data_node_st asn1_data_node_st;
+
+/***********************************/
+/* Fixed constants */
+/***********************************/
+
+/**
+ * ASN1_MAX_ERROR_DESCRIPTION_SIZE:
+ *
+ * Maximum number of characters
+ * of a description message
+ * (null character included).
+ */
+# define ASN1_MAX_ERROR_DESCRIPTION_SIZE 128
+
+/***********************************/
+/* Functions definitions */
+/***********************************/
+
+ extern ASN1_API int
+ asn1_parser2tree (const char *file,
+ asn1_node * definitions, char *error_desc);
+
+ extern ASN1_API int
+ asn1_parser2array (const char *inputFileName,
+ const char *outputFileName,
+ const char *vectorName, char *error_desc);
+
+ extern ASN1_API int
+ asn1_array2tree (const asn1_static_node * array,
+ asn1_node * definitions, char *errorDescription);
+
+ extern ASN1_API void
+ asn1_print_structure (FILE * out, asn1_node_const structure,
+ const char *name, int mode);
+
+ extern ASN1_API int
+ asn1_create_element (asn1_node_const definitions,
+ const char *source_name, asn1_node * element);
+
+ extern ASN1_API int asn1_delete_structure (asn1_node * structure);
+
+ extern ASN1_API int asn1_delete_structure2 (asn1_node * structure,
+ unsigned int flags);
+
+ extern ASN1_API int
+ asn1_delete_element (asn1_node structure, const char *element_name);
+
+ extern ASN1_API int
+ asn1_write_value (asn1_node node_root, const char *name,
+ const void *ivalue, int len);
+
+ extern ASN1_API int
+ asn1_read_value (asn1_node_const root, const char *name,
+ void *ivalue, int *len);
+
+ extern ASN1_API int
+ asn1_read_value_type (asn1_node_const root, const char *name,
+ void *ivalue, int *len, unsigned int *etype);
+
+ extern ASN1_API int
+ asn1_read_node_value (asn1_node_const node, asn1_data_node_st * data);
+
+ extern ASN1_API int
+ asn1_number_of_elements (asn1_node_const element, const char *name,
+ int *num);
+
+ extern ASN1_API int
+ asn1_der_coding (asn1_node_const element, const char *name,
+ void *ider, int *len, char *ErrorDescription);
+
+ extern ASN1_API int
+ asn1_der_decoding2 (asn1_node * element, const void *ider,
+ int *max_ider_len, unsigned int flags,
+ char *errorDescription);
+
+ extern ASN1_API int
+ asn1_der_decoding (asn1_node * element, const void *ider,
+ int ider_len, char *errorDescription);
+
+/* Do not use. Use asn1_der_decoding() instead. */
+ extern ASN1_API int
+ asn1_der_decoding_element (asn1_node * structure,
+ const char *elementName,
+ const void *ider, int len,
+ char *errorDescription)
+ _ASN1_GCC_ATTR_DEPRECATED;
+
+ extern ASN1_API int
+ asn1_der_decoding_startEnd (asn1_node element,
+ const void *ider, int ider_len,
+ const char *name_element,
+ int *start, int *end);
+
+ extern ASN1_API int
+ asn1_expand_any_defined_by (asn1_node_const definitions,
+ asn1_node * element);
+
+ extern ASN1_API int
+ asn1_expand_octet_string (asn1_node_const definitions,
+ asn1_node * element,
+ const char *octetName, const char *objectName);
+
+ extern ASN1_API int
+ asn1_read_tag (asn1_node_const root, const char *name,
+ int *tagValue, int *classValue);
+
+ extern ASN1_API const char *asn1_find_structure_from_oid (asn1_node_const
+ definitions,
+ const char
+ *oidValue);
+
+ __LIBTASN1_PURE__
+ extern ASN1_API const char *asn1_check_version (const char *req_version);
+
+ __LIBTASN1_PURE__ extern ASN1_API const char *asn1_strerror (int error);
+
+ extern ASN1_API void asn1_perror (int error);
+
+# define ASN1_MAX_TAG_SIZE 4
+# define ASN1_MAX_LENGTH_SIZE 9
+# define ASN1_MAX_TL_SIZE (ASN1_MAX_TAG_SIZE+ASN1_MAX_LENGTH_SIZE)
+ extern ASN1_API long
+ asn1_get_length_der (const unsigned char *der, int der_len, int *len);
+
+ extern ASN1_API long
+ asn1_get_length_ber (const unsigned char *ber, int ber_len, int *len);
+
+ extern ASN1_API void
+ asn1_length_der (unsigned long int len, unsigned char *der, int *der_len);
+
+/* Other utility functions. */
+
+ extern ASN1_API
+ int asn1_decode_simple_der (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len,
+ const unsigned char **str,
+ unsigned int *str_len);
+
+ extern ASN1_API
+ int asn1_decode_simple_ber (unsigned int etype, const unsigned char *der,
+ unsigned int _der_len,
+ unsigned char **str,
+ unsigned int *str_len, unsigned int *ber_len);
+
+ extern ASN1_API int
+ asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
+ unsigned int str_len, unsigned char *tl,
+ unsigned int *tl_len);
+
+ extern ASN1_API asn1_node
+ asn1_find_node (asn1_node_const pointer, const char *name);
+
+ extern ASN1_API int
+ asn1_copy_node (asn1_node dst, const char *dst_name,
+ asn1_node_const src, const char *src_name);
+ extern ASN1_API asn1_node
+ asn1_dup_node (asn1_node_const src, const char *src_name);
+
+/* Internal and low-level DER utility functions. */
+
+ extern ASN1_API int
+ asn1_get_tag_der (const unsigned char *der, int der_len,
+ unsigned char *cls, int *len, unsigned long *tag);
+
+ extern ASN1_API void
+ asn1_octet_der (const unsigned char *str, int str_len,
+ unsigned char *der, int *der_len);
+
+ extern ASN1_API int
+ asn1_get_octet_der (const unsigned char *der, int der_len,
+ int *ret_len, unsigned char *str,
+ int str_size, int *str_len);
+
+ extern ASN1_API void asn1_bit_der (const unsigned char *str, int bit_len,
+ unsigned char *der, int *der_len);
+
+ extern ASN1_API int
+ asn1_get_bit_der (const unsigned char *der, int der_len,
+ int *ret_len, unsigned char *str,
+ int str_size, int *bit_len);
+
+ extern ASN1_API int
+ asn1_get_object_id_der (const unsigned char *der,
+ int der_len, int *ret_len,
+ char *str, int str_size);
+
+ extern ASN1_API int
+ asn1_object_id_der (const char *str, unsigned char *der, int *der_len,
+ unsigned flags);
+
+/* Compatibility types */
+
+/**
+ * asn1_retCode:
+ *
+ * Type formerly returned by libtasn1 functions.
+ *
+ * Deprecated: 3.0: Use int instead.
+ */
+ typedef int asn1_retCode _ASN1_GCC_ATTR_DEPRECATED;
+
+/**
+ * node_asn_struct:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_node instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define node_asn_struct _Pragma ("GCC warning \"'node_asn_struct' macro is deprecated, use 'asn1_node' instead.\"") asn1_node_st
+# else
+# define node_asn_struct asn1_node_st
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * node_asn:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_node instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define node_asn _Pragma ("GCC warning \"'node_asn' macro is deprecated, use 'asn1_node' instead.\"") asn1_node_st
+# else
+# define node_asn asn1_node_st
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * ASN1_TYPE:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_node instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define ASN1_TYPE _Pragma ("GCC warning \"'ASN1_TYPE' macro is deprecated, use 'asn1_node' instead.\"") asn1_node
+# else
+# define ASN1_TYPE asn1_node
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * ASN1_TYPE_EMPTY:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use NULL instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define ASN1_TYPE_EMPTY _Pragma ("GCC warning \"'ASN1_TYPE_EMPTY' macro is deprecated, use 'NULL' instead.\"") NULL
+# else
+# define ASN1_TYPE_EMPTY NULL
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * static_struct_asn:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_static_node instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define static_struct_asn _Pragma ("GCC warning \"'static_struct_asn' macro is deprecated, use 'asn1_static_node_st' instead.\"") asn1_static_node_st
+# else
+# define static_struct_asn asn1_static_node_st
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * ASN1_ARRAY_TYPE:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_static_node instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define ASN1_ARRAY_TYPE _Pragma ("GCC warning \"'ASN1_ARRAY_TYPE' macro is deprecated, use 'asn1_static_node' instead.\"") asn1_static_node
+# else
+# define ASN1_ARRAY_TYPE asn1_static_node
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * asn1_static_node_t:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_static_node instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define asn1_static_node_t _Pragma ("GCC warning \"'asn1_static_node_t' macro is deprecated, use 'asn1_static_node' instead.\"") asn1_static_node
+# else
+# define asn1_static_node_t asn1_static_node
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * node_data_struct:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_data_node_st instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define node_data_struct _Pragma ("GCC warning \"'node_data_struct' macro is deprecated, use 'asn1_data_node_st' instead.\"") asn1_data_node_st
+# else
+# define node_data_struct asn1_data_node_st
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+/**
+ * ASN1_DATA_NODE:
+ *
+ * Compat #define.
+ *
+ * Deprecated: 3.0: Use #asn1_data_node_st instead.
+ */
+# ifndef ASN1_DISABLE_DEPRECATED
+# if _ASN1_GCC_VERSION >= 30100
+# define ASN1_DATA_NODE _Pragma ("GCC warning \"'asn1_static_node_t' macro is deprecated, use 'asn1_static_node' instead.\"") asn1_data_node_st
+# else
+# define ASN1_DATA_NODE asn1_data_node_st
+# endif
+# endif /* !ASN1_DISABLE_DEPRECATED */
+
+# ifdef __cplusplus
+}
+# endif
+
+#endif /* LIBTASN1_H */
diff --git a/grub-core/lib/libtasn1/tests/CVE-2018-1000654-1_asn1_tab.h b/grub-core/lib/libtasn1/tests/CVE-2018-1000654-1_asn1_tab.h
new file mode 100644
index 000000000..e7930136c
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/CVE-2018-1000654-1_asn1_tab.h
@@ -0,0 +1,32 @@
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <libtasn1.h>
+
+const asn1_static_node CVE_2018_1000654_1_asn1_tab[] = {
+ { "TEST_TREE", 536875024, NULL },
+ { NULL, 1610612748, NULL },
+ { "iso", 1073741825, "1"},
+ { "identified-organization", 1073741825, "3"},
+ { "dod", 1073741825, "6"},
+ { "internet", 1073741825, "1"},
+ { "security", 1073741825, "5"},
+ { "mechanisms", 1073741825, "5"},
+ { "pkix", 1073741825, "7"},
+ { "id-mod", 1073741825, "0"},
+ { "id-pkix1-implicit-88", 1, "2"},
+ { "id-xnyTest", 1879048204, NULL },
+ { NULL, 1073741825, "id-ix"},
+ { NULL, 1073741825, "29"},
+ { NULL, 1, "1"},
+ { "id-ix", 1880096780, "OBJECR"},
+ { NULL, 1073741825, "id-ix"},
+ { NULL, 1073741825, "29"},
+ { NULL, 1, "2"},
+ { "id-xnyTest", 805306380, NULL },
+ { NULL, 1073741825, "id-ix"},
+ { NULL, 1073741825, "29"},
+ { NULL, 1, "1"},
+ { NULL, 0, NULL }
+};
diff --git a/grub-core/lib/libtasn1/tests/CVE-2018-1000654-2_asn1_tab.h b/grub-core/lib/libtasn1/tests/CVE-2018-1000654-2_asn1_tab.h
new file mode 100644
index 000000000..e8170f5d5
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/CVE-2018-1000654-2_asn1_tab.h
@@ -0,0 +1,36 @@
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <libtasn1.h>
+
+const asn1_static_node CVE_2018_1000654_2_asn1_tab[] = {
+ { "TEST_TREE", 536875024, NULL },
+ { NULL, 1610612748, NULL },
+ { "iso", 1073741825, "1"},
+ { "identified-organization", 1073741825, "3"},
+ { "dod", 1073741825, "6"},
+ { "internet", 1073741825, "1"},
+ { "security", 1073741825, "5"},
+ { "mechanisms", 1073741825, "5"},
+ { "pkix", 1073741825, "7"},
+ { "id-mod", 1073741825, "0"},
+ { "id-pkix1-implicit-88", 1, "2"},
+ { "id-oneTest", 1879048204, NULL },
+ { NULL, 1073741825, "id-two"},
+ { NULL, 1073741825, "9"},
+ { NULL, 1, "1"},
+ { "id-two", 1879048204, NULL },
+ { NULL, 1073741825, "id-three"},
+ { NULL, 1073741825, "2"},
+ { NULL, 1, "2"},
+ { "id-three", 1879048204, NULL },
+ { NULL, 1073741825, "id-four"},
+ { NULL, 1073741825, "3"},
+ { NULL, 1, "3"},
+ { "id-four", 805306380, NULL },
+ { NULL, 1073741825, "id-two"},
+ { NULL, 1073741825, "3"},
+ { NULL, 1, "3"},
+ { NULL, 0, NULL }
+};
diff --git a/grub-core/lib/libtasn1/tests/CVE-2018-1000654.c b/grub-core/lib/libtasn1/tests/CVE-2018-1000654.c
new file mode 100644
index 000000000..0c22b7012
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/CVE-2018-1000654.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2002-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/****************************************************************/
+/* Description: reproducer for CVE-2018-1000654 */
+/****************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "CVE-2018-1000654-1_asn1_tab.h"
+#include "CVE-2018-1000654-2_asn1_tab.h"
+
+int
+main (int argc, char *argv[])
+{
+ int result, verbose = 0;
+ asn1_node definitions = NULL;
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+
+ if (argc > 1)
+ verbose = 1;
+
+ printf ("Test 1\n");
+
+ result =
+ asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions,
+ errorDescription);
+ if (result != ASN1_RECURSION)
+ {
+ asn1_perror (result);
+ printf ("ErrorDescription = %s\n\n", errorDescription);
+ exit (1);
+ }
+
+ asn1_delete_structure (&definitions);
+
+ printf ("Test 2\n");
+
+ result =
+ asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions,
+ errorDescription);
+ if (result != ASN1_RECURSION)
+ {
+ asn1_perror (result);
+ printf ("ErrorDescription = %s\n\n", errorDescription);
+ exit (1);
+ }
+
+ asn1_delete_structure (&definitions);
+
+ if (verbose)
+ printf ("Success\n");
+ exit (0);
+}
diff --git a/grub-core/lib/libtasn1/tests/Test_overflow.c b/grub-core/lib/libtasn1/tests/Test_overflow.c
new file mode 100644
index 000000000..c61dea4bb
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/Test_overflow.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/* Written by Simon Josefsson */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include "libtasn1.h"
+
+int
+main (int argc, char **argv)
+{
+ /* Test that values larger than long are rejected. This has worked
+ fine with all versions of libtasn1. */
+ int verbose = 0;
+
+ if (argc > 1)
+ verbose = 1;
+
+ {
+ unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
+ long l;
+ int len;
+
+ l = asn1_get_length_der (der, sizeof der, &len);
+
+ if (l == -2L)
+ {
+ if (verbose)
+ puts ("OK: asn1_get_length_der bignum");
+ }
+ else
+ {
+ printf ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
+ return 1;
+ }
+ }
+
+ /* Test that values larger than int but smaller than long are
+ rejected. This limitation was introduced with libtasn1 2.12. */
+ if (LONG_MAX > INT_MAX)
+ {
+ unsigned long num = ((long) UINT_MAX) << 2;
+ unsigned char der[20];
+ int der_len;
+ long l;
+ int len;
+
+ asn1_length_der (num, der, &der_len);
+
+ l = asn1_get_length_der (der, der_len, &len);
+
+ if (l == -2L)
+ {
+ if (verbose)
+ puts ("OK: asn1_get_length_der intnum");
+ }
+ else
+ {
+ printf ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l,
+ len);
+ return 1;
+ }
+ }
+
+ /* Test that values larger than would fit in the input string are
+ rejected. This problem was fixed in libtasn1 2.12. */
+ {
+ unsigned long num = 64;
+ unsigned char der[20];
+ int der_len;
+ long l;
+ int len;
+
+ asn1_length_der (num, der, &der_len);
+
+ der_len = sizeof (der);
+ l = asn1_get_length_der (der, der_len, &len);
+
+ if (l == -4L)
+ {
+ if (verbose)
+ puts ("OK: asn1_get_length_der overflow-small");
+ }
+ else
+ {
+ printf ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n",
+ l, len);
+ return 1;
+ }
+ }
+
+ /* Test that values larger than would fit in the input string are
+ rejected. This problem was fixed in libtasn1 2.12. */
+ {
+ unsigned long num = 1073741824;
+ unsigned char der[20];
+ int der_len;
+ long l;
+ int len;
+
+ asn1_length_der (num, der, &der_len);
+
+ der_len = sizeof (der);
+ l = asn1_get_length_der (der, der_len, &len);
+
+ if (l == -4L)
+ {
+ if (verbose)
+ puts ("OK: asn1_get_length_der overflow-large1");
+ }
+ else
+ {
+ printf ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n",
+ l, len);
+ return 1;
+ }
+ }
+
+ /* Test that values larger than would fit in the input string are
+ rejected. This problem was fixed in libtasn1 2.12. */
+ {
+ unsigned long num = 2147483649;
+ unsigned char der[20];
+ int der_len;
+ long l;
+ int len;
+
+ asn1_length_der (num, der, &der_len);
+
+ der_len = sizeof (der);
+ l = asn1_get_length_der (der, der_len, &len);
+
+ if (l == -2L)
+ {
+ if (verbose)
+ puts ("OK: asn1_get_length_der overflow-large2");
+ }
+ else
+ {
+ printf ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n",
+ l, len);
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/grub-core/lib/libtasn1/tests/Test_simple.c b/grub-core/lib/libtasn1/tests/Test_simple.c
new file mode 100644
index 000000000..6cd07e069
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/Test_simple.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2011-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Simon Josefsson
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libtasn1.h"
+
+struct tv
+{
+ int bitlen;
+ const char *bitstr;
+ int derlen;
+ const char *der;
+};
+
+static const struct tv tv[] = {
+ {0, "", 2, "\x01\x00"},
+ {1, "\x00", 3, "\x02\x07\x00"},
+ {2, "\x00", 3, "\x02\x06\x00"},
+ {3, "\x00", 3, "\x02\x05\x00"},
+ {4, "\x00", 3, "\x02\x04\x00"},
+ {5, "\x00", 3, "\x02\x03\x00"},
+ {6, "\x00", 3, "\x02\x02\x00"},
+ {7, "\x00", 3, "\x02\x01\x00"},
+ {8, "\x00\x00", 3, "\x02\x00\x00"},
+ {9, "\x00\x00", 4, "\x03\x07\x00\x00"},
+ {10, "\x00\x00", 4, "\x03\x06\x00\x00"},
+ {11, "\x00\x00", 4, "\x03\x05\x00\x00"},
+ {12, "\x00\x00", 4, "\x03\x04\x00\x00"},
+ {13, "\x00\x00", 4, "\x03\x03\x00\x00"},
+ {14, "\x00\x00", 4, "\x03\x02\x00\x00"},
+ {15, "\x00\x00", 4, "\x03\x01\x00\x00"},
+ {16, "\x00\x00", 4, "\x03\x00\x00\x00"},
+ {17, "\x00\x00\x00", 5, "\x04\x07\x00\x00\x00"},
+ {18, "\x00\x00\x00", 5, "\x04\x06\x00\x00\x00"},
+ {19, "\x00\x00\x00", 5, "\x04\x05\x00\x00\x00"},
+ {1, "\xFF", 3, "\x02\x07\x80"},
+ {2, "\xFF", 3, "\x02\x06\xc0"},
+ {3, "\xFF", 3, "\x02\x05\xe0"},
+ {4, "\xFF", 3, "\x02\x04\xf0"},
+ {5, "\xFF", 3, "\x02\x03\xf8"},
+ {6, "\xFF", 3, "\x02\x02\xfc"},
+ {7, "\xFF", 3, "\x02\x01\xfe"},
+ {8, "\xFF\xFF", 3, "\x02\x00\xff"},
+ {9, "\xFF\xFF", 4, "\x03\x07\xff\x80"},
+ {10, "\xFF\xFF", 4, "\x03\x06\xff\xc0"},
+ {11, "\xFF\xFF", 4, "\x03\x05\xff\xe0"},
+ {12, "\xFF\xFF", 4, "\x03\x04\xff\xf0"},
+ {13, "\xFF\xFF", 4, "\x03\x03\xff\xf8"},
+ {14, "\xFF\xFF", 4, "\x03\x02\xff\xfc"},
+ {15, "\xFF\xFF", 4, "\x03\x01\xff\xfe"},
+ {16, "\xFF\xFF", 4, "\x03\x00\xff\xff"},
+ {17, "\xFF\xFF\xFF", 5, "\x04\x07\xff\xff\x80"},
+ {18, "\xFF\xFF\xFF", 5, "\x04\x06\xff\xff\xc0"},
+ {19, "\xFF\xFF\xFF", 5, "\x04\x05\xff\xff\xe0"},
+};
+
+int
+main (int argc, char *argv[])
+{
+ int result;
+ unsigned char der[100];
+ unsigned char str[100];
+ int der_len = sizeof (der);
+ int str_size = sizeof (str);
+ int ret_len, bit_len;
+ size_t i;
+
+ {
+ unsigned int etype = 38;
+ unsigned int my_str_len = 10;
+ unsigned char my_str[10];
+ unsigned int tl_len = 10;
+ unsigned char tl[10];
+
+ /* https://gitlab.com/gnutls/libtasn1/-/issues/32 */
+ result = asn1_encode_simple_der (etype, my_str, my_str_len, tl, &tl_len);
+ if (result != ASN1_VALUE_NOT_VALID)
+ {
+ fprintf (stderr, "asn1_encode_simple_der out of range etype\n");
+ return 1;
+ }
+ }
+
+ /* Dummy test */
+
+ asn1_bit_der (NULL, 0, der, &der_len);
+ result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len);
+ if (result != ASN1_GENERIC_ERROR)
+ {
+ fprintf (stderr, "asn1_get_bit_der zero\n");
+ return 1;
+ }
+
+ /* Encode short strings with increasing bit lengths */
+
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
+ /* Encode */
+
+ asn1_bit_der ((const unsigned char *) tv[i].bitstr, tv[i].bitlen,
+ der, &der_len);
+
+#if 0
+ {
+ size_t j;
+ for (j = 0; j < der_len; j++)
+ printf ("\\x%02x", der[j]);
+ printf ("\n");
+ }
+#endif
+
+ if (der_len != tv[i].derlen || memcmp (der, tv[i].der, der_len) != 0)
+ {
+ fprintf (stderr, "asn1_bit_der iter %lu\n", (unsigned long) i);
+ return 1;
+ }
+
+ /* Decode it */
+
+ result = asn1_get_bit_der (der, der_len, &ret_len, str,
+ str_size, &bit_len);
+ if (result != ASN1_SUCCESS || ret_len != tv[i].derlen
+ || bit_len != tv[i].bitlen)
+ {
+ fprintf (stderr, "asn1_get_bit_der iter %lu, err: %d\n",
+ (unsigned long) i, result);
+ return 1;
+ }
+ }
+
+
+ /* Decode sample from "A Layman's Guide to a Subset of ASN.1, BER,
+ and DER" section 5.4 "BIT STRING": "The BER encoding of the BIT
+ STRING value "011011100101110111" can be any of the following,
+ among others, depending on the choice of padding bits, the form
+ of length octets [...]".
+ */
+
+ /* 03 04 06 6e 5d c0 DER encoding */
+
+ memcpy (der, "\x04\x06\x6e\x5d\xc0", 5);
+ der_len = 5;
+
+ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
+ if (result != ASN1_SUCCESS || ret_len != 5
+ || bit_len != 18 || memcmp (str, "\x6e\x5d\xc0", 3) != 0)
+ {
+ fprintf (stderr, "asn1_get_bit_der example\n");
+ return 1;
+ }
+
+ der_len = sizeof (der);
+ asn1_bit_der (str, bit_len, der, &der_len);
+ if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+ fprintf (stderr, "asn1_bit_der example roundtrip\n");
+ return 1;
+ }
+
+ /* 03 04 06 6e 5d e0 padded with "100000" */
+
+ memcpy (der, "\x04\x06\x6e\x5d\xe0", 5);
+ der_len = 5;
+
+ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
+ if (result != ASN1_SUCCESS || ret_len != 5
+ || bit_len != 18 || memcmp (str, "\x6e\x5d\xe0", 3) != 0)
+ {
+ fprintf (stderr, "asn1_get_bit_der example padded\n");
+ return 1;
+ }
+
+ der_len = sizeof (der);
+ asn1_bit_der (str, bit_len, der, &der_len);
+ if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+ fprintf (stderr, "asn1_bit_der example roundtrip\n");
+ return 1;
+ }
+
+ /* 03 81 04 06 6e 5d c0 long form of length octets */
+
+ memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6);
+ der_len = 6;
+
+ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
+
+ if (result != ASN1_SUCCESS || ret_len != 6
+ || bit_len != 18 || memcmp (str, "\x6e\x5d\xc0", 3) != 0)
+ {
+ fprintf (stderr, "asn1_get_bit_der example long form\n");
+ return 1;
+ }
+
+ der_len = sizeof (der);
+ asn1_bit_der (str, bit_len, der, &der_len);
+ if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+ fprintf (stderr, "asn1_bit_der example roundtrip\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/grub-core/lib/libtasn1/tests/Test_strings.c b/grub-core/lib/libtasn1/tests/Test_strings.c
new file mode 100644
index 000000000..27f7215e1
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/Test_strings.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Simon Josefsson
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libtasn1.h"
+
+struct tv
+{
+ unsigned int etype;
+ unsigned int str_len;
+ const void *str;
+ unsigned int der_len;
+ const void *der;
+};
+
+static const struct tv tv[] = {
+ {ASN1_ETYPE_IA5_STRING, 20,
+ "\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72",
+ 22,
+ "\x16\x14\x63\x73\x63\x61\x40\x70\x61\x73\x73\x70\x6f\x72\x74\x2e\x67\x6f\x76\x2e\x67\x72"},
+ {ASN1_ETYPE_PRINTABLE_STRING, 5, "\x4e\x69\x6b\x6f\x73",
+ 7, "\x13\x05\x4e\x69\x6b\x6f\x73"},
+ {ASN1_ETYPE_UTF8_STRING, 12, "Αττική",
+ 14, "\x0c\x0c\xce\x91\xcf\x84\xcf\x84\xce\xb9\xce\xba\xce\xae"},
+ {ASN1_ETYPE_TELETEX_STRING, 15,
+ "\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e",
+ 17,
+ "\x14\x0f\x53\x69\x6d\x6f\x6e\x20\x4a\x6f\x73\x65\x66\x73\x73\x6f\x6e"},
+ {ASN1_ETYPE_OCTET_STRING, 36,
+ "\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A",
+ 38,
+ "\x04\x24\x30\x22\x80\x0F\x32\x30\x31\x31\x30\x38\x32\x31\x30\x38\x30\x30\x30\x36\x5A\x81\x0F\x32\x30\x31\x31\x30\x38\x32\x33\x32\x30\x35\x39\x35\x39\x5A"}
+};
+
+#define SSTR(x) sizeof(x)-1,x
+static const struct tv ber[] = {
+ {ASN1_ETYPE_OCTET_STRING,
+ SSTR ("\xa0\xa0"),
+ SSTR ("\x24\x80\x04\x82\x00\x02\xa0\xa0\x00\x00")},
+ {ASN1_ETYPE_OCTET_STRING,
+ SSTR ("\xa0\xa0\xb0\xb0\xb0"),
+ SSTR
+ ("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x00\x00")},
+ {ASN1_ETYPE_OCTET_STRING,
+ SSTR ("\xa0\xa0\xb0\xb0\xb0\xa1\xa1"),
+ SSTR
+ ("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x00\x00\x00\x00")},
+ {ASN1_ETYPE_OCTET_STRING,
+ SSTR ("\xa0\xa0\xb0\xb0\xb0\xa1\xa1\xc1"),
+ SSTR
+ ("\x24\x80\x04\x82\x00\x02\xa0\xa0\x04\x82\x00\x03\xb0\xb0\xb0\x24\x80\x04\x82\x00\x02\xa1\xa1\x04\x82\x00\x01\xc1\x00\x00\x00\x00")},
+};
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+ unsigned char tl[ASN1_MAX_TL_SIZE];
+ unsigned int tl_len, der_len, str_len;
+ const unsigned char *str;
+ unsigned char *b;
+ unsigned int i;
+
+ /* Dummy test */
+
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
+ /* Encode */
+ tl_len = sizeof (tl);
+ ret = asn1_encode_simple_der (tv[i].etype, tv[i].str, tv[i].str_len,
+ tl, &tl_len);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Encoding error in %u: %s\n", i,
+ asn1_strerror (ret));
+ return 1;
+ }
+ der_len = tl_len + tv[i].str_len;
+
+ if (der_len != tv[i].der_len || memcmp (tl, tv[i].der, tl_len) != 0)
+ {
+ fprintf (stderr,
+ "DER encoding differs in %u! (size: %u, expected: %u)\n",
+ i, der_len, tv[i].der_len);
+ return 1;
+ }
+
+ /* decoding */
+ ret =
+ asn1_decode_simple_der (tv[i].etype, tv[i].der, tv[i].der_len, &str,
+ &str_len);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Decoding error in %u: %s\n", i,
+ asn1_strerror (ret));
+ return 1;
+ }
+
+ if (str_len != tv[i].str_len || memcmp (str, tv[i].str, str_len) != 0)
+ {
+ fprintf (stderr,
+ "DER decoded data differ in %u! (size: %u, expected: %u)\n",
+ i, der_len, tv[i].str_len);
+ return 1;
+ }
+ }
+
+ /* BER decoding */
+ for (i = 0; i < sizeof (ber) / sizeof (ber[0]); i++)
+ {
+ /* decoding */
+ ret =
+ asn1_decode_simple_ber (ber[i].etype, ber[i].der, ber[i].der_len, &b,
+ &str_len, NULL);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "BER decoding error in %u: %s\n", i,
+ asn1_strerror (ret));
+ return 1;
+ }
+
+ if (str_len != ber[i].str_len || memcmp (b, ber[i].str, str_len) != 0)
+ {
+ fprintf (stderr,
+ "BER decoded data differ in %u! (size: %u, expected: %u)\n",
+ i, str_len, ber[i].str_len);
+ return 1;
+ }
+ free (b);
+ }
+
+
+ return 0;
+}
diff --git a/grub-core/lib/libtasn1/tests/object-id-decoding.c b/grub-core/lib/libtasn1/tests/object-id-decoding.c
new file mode 100644
index 000000000..06a6c52a2
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/object-id-decoding.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libtasn1.h"
+
+struct tv
+{
+ int der_len;
+ const unsigned char *der;
+ const char *oid;
+ int expected_error;
+};
+
+static const struct tv tv[] = {
+ {.der_len = 5,
+ .der = (void *) "\x06\x03\x80\x37\x03",
+ .oid = "2.999.3",
+ .expected_error = ASN1_DER_ERROR /* leading 0x80 */
+ },
+ {.der_len = 12,
+ .der = (void *) "\x06\x0a\x2b\x06\x01\x80\x01\x92\x08\x09\x05\x01",
+ .oid = "1.3.6.1.4.1.2312.9.5.1",
+ .expected_error = ASN1_DER_ERROR /* leading 0x80 */
+ },
+ {.der_len = 6,
+ .der = (void *) "\x06\x04\x01\x02\x03\x04",
+ .oid = "0.1.2.3.4",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 5,
+ .der = (void *) "\x06\x03\x51\x02\x03",
+ .oid = "2.1.2.3",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 5,
+ .der = (void *) "\x06\x03\x88\x37\x03",
+ .oid = "2.999.3",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 12,
+ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
+ .oid = "1.3.6.1.4.1.2312.9.5.1",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 19,
+ .der =
+ (void *)
+ "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
+ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 19,
+ .der =
+ (void *)
+ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
+ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
+ .expected_error = ASN1_SUCCESS},
+};
+
+int
+main (int argc, char *argv[])
+{
+ char str[128];
+ int ret, ret_len;
+ size_t i;
+
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
+ /* decode */
+ ret =
+ asn1_get_object_id_der (tv[i].der + 1,
+ tv[i].der_len - 1, &ret_len, str,
+ sizeof (str));
+ if (ret != tv[i].expected_error)
+ {
+ fprintf (stderr,
+ "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
+ __LINE__, (unsigned long) i, asn1_strerror (ret),
+ tv[i].expected_error);
+ return 1;
+ }
+
+ if (tv[i].expected_error != ASN1_SUCCESS)
+ continue;
+
+ if (ret_len != tv[i].der_len - 1)
+ {
+ fprintf (stderr,
+ "%d: iter %lu: error in DER, length returned is %d, had %d\n",
+ __LINE__, (unsigned long) i, ret_len, tv[i].der_len - 1);
+ return 1;
+ }
+
+ if (strcmp (tv[i].oid, str) != 0)
+ {
+ fprintf (stderr,
+ "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
+ __LINE__, (unsigned long) i, str, tv[i].oid);
+ return 1;
+ }
+
+ }
+
+ return 0;
+}
diff --git a/grub-core/lib/libtasn1/tests/object-id-encoding.c b/grub-core/lib/libtasn1/tests/object-id-encoding.c
new file mode 100644
index 000000000..1a3396986
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/object-id-encoding.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 Nikos Mavrogiannopoulos
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libtasn1.h"
+
+struct tv
+{
+ int der_len;
+ const unsigned char *der;
+ const char *oid;
+ int expected_error;
+};
+
+static const struct tv tv[] = {
+ {.der_len = 0,
+ .der = (void *) "",
+ .oid = "5.999.3",
+ .expected_error = ASN1_VALUE_NOT_VALID /* cannot start with 5 */
+ },
+ {.der_len = 0,
+ .der = (void *) "",
+ .oid = "0.48.9",
+ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 48 */
+ },
+ {.der_len = 0,
+ .der = (void *) "",
+ .oid = "1.40.9",
+ .expected_error = ASN1_VALUE_NOT_VALID /* second field cannot be 40 */
+ },
+ {.der_len = 4,
+ .der = (void *) "\x06\x02\x4f\x63",
+ .oid = "1.39.99",
+ .expected_error = ASN1_SUCCESS,
+ },
+ {.der_len = 6,
+ .der = (void *) "\x06\x04\x01\x02\x03\x04",
+ .oid = "0.1.2.3.4",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 5,
+ .der = (void *) "\x06\x03\x51\x02\x03",
+ .oid = "2.1.2.3",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 5,
+ .der = (void *) "\x06\x03\x88\x37\x03",
+ .oid = "2.999.3",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 12,
+ .der = (void *) "\x06\x0a\x2b\x06\x01\x04\x01\x92\x08\x09\x05\x01",
+ .oid = "1.3.6.1.4.1.2312.9.5.1",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 19,
+ .der =
+ (void *)
+ "\x06\x11\xfa\x80\x00\x00\x00\x0e\x01\x0e\xfa\x80\x00\x00\x00\x0e\x63\x6f\x6d",
+ .oid = "2.1998768.0.0.14.1.14.1998848.0.0.14.99.111.109",
+ .expected_error = ASN1_SUCCESS},
+ {.der_len = 19,
+ .der =
+ (void *)
+ "\x06\x11\x2b\x06\x01\x04\x01\x92\x08\x09\x02\xaa\xda\xbe\xbe\xfa\x72\x01\x07",
+ .oid = "1.3.6.1.4.1.2312.9.2.1467399257458.1.7",
+ .expected_error = ASN1_SUCCESS},
+};
+
+int
+main (int argc, char *argv[])
+{
+ unsigned char der[128];
+ int ret, der_len, i, j;
+
+ for (i = 0; i < (int) (sizeof (tv) / sizeof (tv[0])); i++)
+ {
+ der_len = sizeof (der);
+ ret = asn1_object_id_der (tv[i].oid, der, &der_len, 0);
+ if (ret != ASN1_SUCCESS)
+ {
+ if (ret == tv[i].expected_error)
+ continue;
+ fprintf (stderr,
+ "%d: iter %lu, encoding of OID failed: %s\n",
+ __LINE__, (unsigned long) i, asn1_strerror (ret));
+ return 1;
+ }
+ else if (ret != tv[i].expected_error)
+ {
+ fprintf (stderr,
+ "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
+ __LINE__, (unsigned long) i, tv[i].oid);
+ return 1;
+ }
+
+ if (der_len != tv[i].der_len || memcmp (der, tv[i].der, der_len) != 0)
+ {
+ fprintf (stderr,
+ "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
+ __LINE__, (unsigned long) i, tv[i].oid, der_len,
+ tv[i].der_len);
+ fprintf (stderr, "\nGot:\t\t");
+ for (j = 0; j < der_len; j++)
+ fprintf (stderr, "%.2x", der[j]);
+
+ fprintf (stderr, "\nExpected:\t");
+ for (j = 0; j < tv[i].der_len; j++)
+ fprintf (stderr, "%.2x", tv[i].der[j]);
+ fprintf (stderr, "\n");
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/grub-core/lib/libtasn1/tests/octet-string.c b/grub-core/lib/libtasn1/tests/octet-string.c
new file mode 100644
index 000000000..69eb18a62
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/octet-string.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Simon Josefsson and Nikos Mavrogiannopoulos
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "libtasn1.h"
+
+struct tv
+{
+ const char *name;
+ int der_len;
+ const unsigned char *der_str;
+ int len;
+ const unsigned char *string;
+ int expected_error;
+ int ber;
+};
+
+static const struct tv tv[] = {
+ {.name = "primitive octet strings",
+ .der_len = 10,
+ .der_str = (void *) "\x04\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .len = 8,
+ .string = (void *) "\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .ber = 0},
+ {.der_len = 22,
+ .der_str =
+ (void *)
+ "\x04\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
+ .len = 20,
+ .string =
+ (void *)
+ "\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27"},
+
+ {.name = "long type of length",
+ .der_len = 23,
+ .der_str =
+ (void *)
+ "\x04\x81\x14\x13\x00\xd9\xa8\x47\xf7\xf2\x1c\xf4\xb0\xec\x5f\xc1\x73\xe5\x1b\x25\xc2\x62\x27",
+ .len = 20,
+ .string =
+ (void *)
+ "\x13\x00\xD9\xA8\x47\xF7\xF2\x1C\xF4\xB0\xEC\x5F\xC1\x73\xE5\x1B\x25\xC2\x62\x27",
+ .ber = 1},
+ {.der_len = 11,
+ .der_str = (void *) "\x04\x81\x08\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .len = 8,
+ .string = (void *) "\x01\x23\x45\x67\x89\xab\xcd\xef",
+ .ber = 1},
+
+ {.name = "constructed - indefinite",
+ .der_len = 11,
+ .der_str = (void *) "\x24\x80\x04\x05\x01\x02\x03\x04\x05\x00\x00",
+ .len = 5,
+ .string = (void *) "\x01\x02\x03\x04\x05",
+ .ber = 1,
+ },
+
+ {.name = "constructed - definite - concat",
+ .der_len = 12,
+ .der_str = (void *) "\x24\x0a\x04\x04\x0a\x0b\x0c\x0d\x04\x02\x0e\x0f",
+ .len = 6,
+ .string = (void *) "\x0a\x0b\x0c\x0d\x0e\x0f",
+ .ber = 1,
+ },
+ {.name = "constructed - definite - recursive",
+ .der_len = 15,
+ .der_str =
+ (void *) "\x24\x0d\x04\x04\x0a\x0b\x0c\x0d\x24\x05\x04\x00\x04\x01\x0f",
+ .len = 5,
+ .string = (void *) "\x0a\x0b\x0c\x0d\x0f",
+ .ber = 1,
+ },
+ {.name = "constructed - definite - single",
+ .der_len = 7,
+ .der_str = (void *) "\x24\x05\x04\x03\x01\x02\x03",
+ .len = 3,
+ .string = (void *) "\x01\x02\x03",
+ .ber = 1,
+ },
+
+ /* a large amount of recursive indefinite encoding */
+ {.name = "a large amount of recursive indefinite encoding",
+ .der_len = 29325,
+ .der_str =
+ (void *)
+ "\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80\x24\x80",
+ .len = 0,
+ .ber = 1,
+ .expected_error = ASN1_DER_ERROR}
+};
+
+int
+main (int argc, char *argv[])
+{
+ unsigned char str[100];
+ unsigned char der[100];
+ int der_len = sizeof (der);
+ int str_size = sizeof (str);
+ unsigned char *tmp = NULL;
+ int ret, ret_len, j;
+ size_t i;
+
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
+ /* Decode */
+
+ if (tv[i].ber == 0)
+ {
+ str_size = sizeof (str);
+ ret =
+ asn1_get_octet_der (tv[i].der_str + 1,
+ tv[i].der_len - 1, &ret_len, str,
+ sizeof (str), &str_size);
+ if (ret != tv[i].expected_error)
+ {
+ fprintf (stderr,
+ "%d: asn1_get_octet_der: %s: got %d expected %d\n",
+ __LINE__, tv[i].name, ret, tv[i].expected_error);
+ return 1;
+ }
+ if (tv[i].expected_error)
+ continue;
+
+ if (ret_len != tv[i].der_len - 1)
+ {
+ fprintf (stderr,
+ "%d: error in DER, length returned is %d, had %d\n",
+ __LINE__, ret_len, tv[i].der_len - 1);
+ return 1;
+ }
+
+ if (str_size != tv[i].len
+ || memcmp (tv[i].string, str, tv[i].len) != 0)
+ {
+ fprintf (stderr,
+ "%d: memcmp: %s: got invalid decoding\n",
+ __LINE__, tv[i].name);
+
+ fprintf (stderr, "\nGot:\t\t");
+ for (j = 0; j < str_size; j++)
+ fprintf (stderr, "%.2x", str[j]);
+
+ fprintf (stderr, "\nExpected:\t");
+ for (j = 0; j < tv[i].len; j++)
+ fprintf (stderr, "%.2x", tv[i].string[j]);
+ fprintf (stderr, "\n");
+ return 1;
+ }
+
+ /* Encode */
+ der_len = sizeof (der);
+ asn1_octet_der (str, str_size, der, &der_len);
+
+ if (der_len != tv[i].der_len - 1
+ || memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
+ {
+ fprintf (stderr,
+ "encoding: %s: got invalid encoding\n", tv[i].name);
+ return 1;
+ }
+ }
+
+ ret =
+ asn1_decode_simple_ber (ASN1_ETYPE_OCTET_STRING,
+ tv[i].der_str, tv[i].der_len,
+ &tmp, (unsigned int *) &str_size,
+ (unsigned int *) &der_len);
+ if (ret != tv[i].expected_error)
+ {
+ fprintf (stderr,
+ "%d: asn1_decode_simple_ber: %s: got %s expected %s\n",
+ __LINE__, tv[i].name, asn1_strerror (ret),
+ asn1_strerror (tv[i].expected_error));
+ return 1;
+ }
+ if (tv[i].expected_error)
+ continue;
+
+ if (der_len != tv[i].der_len)
+ {
+ fprintf (stderr,
+ "%d: error: %s: DER, length returned is %d, had %d\n",
+ __LINE__, tv[i].name, der_len, tv[i].der_len);
+ return 1;
+ }
+
+ if (str_size != tv[i].len || memcmp (tv[i].string, tmp, tv[i].len) != 0)
+ {
+ fprintf (stderr,
+ "%d: memcmp: %s: got invalid decoding\n",
+ __LINE__, tv[i].name);
+ fprintf (stderr, "\nGot:\t\t");
+ for (j = 0; j < str_size; j++)
+ fprintf (stderr, "%.2x", tmp[j]);
+
+ fprintf (stderr, "\nExpected:\t");
+ for (j = 0; j < tv[i].len; j++)
+ fprintf (stderr, "%.2x", tv[i].string[j]);
+ fprintf (stderr, "\n");
+ return 1;
+ }
+ free (tmp);
+ tmp = NULL;
+
+ }
+
+ return 0;
+}
diff --git a/grub-core/lib/libtasn1/tests/reproducers.c b/grub-core/lib/libtasn1/tests/reproducers.c
new file mode 100644
index 000000000..a09d8b021
--- /dev/null
+++ b/grub-core/lib/libtasn1/tests/reproducers.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019-2022 Free Software Foundation, Inc.
+ *
+ * This file is part of LIBTASN1.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/****************************************************************/
+/* Description: run reproducers for several fixed issues */
+/****************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <libtasn1.h>
+
+#include <int.h>
+
+/* produces endless loop (fixed by d4b624b2):
+ * The following translates into a single node with all pointers
+ * (right,left,down) set to NULL. */
+const asn1_static_node endless_asn1_tab[] = {
+ {"TEST_TREE", 536875024, NULL},
+ {NULL, 0, NULL}
+};
+
+/* produces memory leak (fixed by f16d1ff9):
+ * 152 bytes in 1 blocks are definitely lost in loss record 1 of 1
+ * at 0x4837B65: calloc (vg_replace_malloc.c:762)
+ * by 0x4851C0D: _asn1_add_static_node (parser_aux.c:71)
+ * by 0x4853AAC: asn1_array2tree (structure.c:200)
+ * by 0x10923B: main (single_node.c:67)
+ */
+const asn1_static_node tab[] = {
+ {"a", CONST_DOWN, ""},
+ {"b", 0, ""},
+ {"c", 0, ""},
+ {NULL, 0, NULL}
+};
+
+int
+main (int argc, char *argv[])
+{
+ int result, verbose = 0;
+ asn1_node definitions = NULL;
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+
+ if (argc > 1)
+ verbose = 1;
+
+ result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription);
+ if (result != ASN1_SUCCESS)
+ {
+ asn1_perror (result);
+ printf ("ErrorDescription = %s\n\n", errorDescription);
+ exit (EXIT_FAILURE);
+ }
+
+ asn1_delete_structure (&definitions);
+
+ definitions = NULL;
+ result = asn1_array2tree (tab, &definitions, errorDescription);
+ if (result != ASN1_SUCCESS)
+ {
+ asn1_perror (result);
+ printf ("ErrorDescription = %s\n\n", errorDescription);
+ exit (EXIT_FAILURE);
+ }
+
+ asn1_delete_structure (&definitions);
+
+ if (verbose)
+ printf ("Success\n");
+
+ exit (EXIT_SUCCESS);
+}
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 03/33] libtasn1: disable code not needed in grub
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 01/33] posix_wrap: tweaks in preparation for libtasn1 Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 02/33] libtasn1: import libtasn1-4.19.0 Gary Lin via Grub-devel
@ 2024-09-06 9:10 ` Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 04/33] libtasn1: replace strcat() with strcpy() in _asn1_str_cat() Gary Lin via Grub-devel
` (31 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
We don't expect to be able to write ASN.1, only read it,
so we can disable some code.
Do that with #if 0/#endif, rather than deletion. This means
that the difference between upstream and grub is smaller,
which should make updating libtasn1 easier in the future.
With these exclusions we also avoid the need for minmax.h,
which is convenient because it means we don't have to
import it from gnulib.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
...asn1-disable-code-not-needed-in-grub.patch | 320 ++++++++++++++++++
1 file changed, 320 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch
diff --git a/grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch b/grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch
new file mode 100644
index 000000000..3203a014c
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch
@@ -0,0 +1,320 @@
+From b927f1b24fe10c57edc9711ff4baa12b013ce351 Mon Sep 17 00:00:00 2001
+From: Daniel Axtens <dja@axtens.net>
+Date: Fri, 1 May 2020 17:12:23 +1000
+Subject: [PATCH 01/12] libtasn1: disable code not needed in grub
+
+We don't expect to be able to write ASN.1, only read it,
+so we can disable some code.
+
+Do that with #if 0/#endif, rather than deletion. This means
+that the difference between upstream and grub is smaller,
+which should make updating libtasn1 easier in the future.
+
+With these exclusions we also avoid the need for minmax.h,
+which is convenient because it means we don't have to
+import it from gnulib.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/lib/libtasn1-grub/lib/coding.c | 12 ++++++++++--
+ grub-core/lib/libtasn1-grub/lib/decoding.c | 2 ++
+ grub-core/lib/libtasn1-grub/lib/element.c | 6 +++---
+ grub-core/lib/libtasn1-grub/lib/errors.c | 3 +++
+ grub-core/lib/libtasn1-grub/lib/structure.c | 10 ++++++----
+ grub-core/lib/libtasn1-grub/libtasn1.h | 15 +++++++++++++++
+ 6 files changed, 39 insertions(+), 9 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1-grub/lib/coding.c b/grub-core/lib/libtasn1-grub/lib/coding.c
+index ea5bc370e..5d03bca9d 100644
+--- a/grub-core/lib/libtasn1-grub/lib/coding.c
++++ b/grub-core/lib/libtasn1-grub/lib/coding.c
+@@ -30,11 +30,11 @@
+ #include "parser_aux.h"
+ #include <gstr.h>
+ #include "element.h"
+-#include "minmax.h"
+ #include <structure.h>
+
+ #define MAX_TAG_LEN 16
+
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /******************************************************/
+ /* Function : _asn1_error_description_value_not_found */
+ /* Description: creates the ErrorDescription string */
+@@ -58,6 +58,7 @@ _asn1_error_description_value_not_found (asn1_node node,
+ Estrcat (ErrorDescription, "' not found");
+
+ }
++#endif
+
+ /**
+ * asn1_length_der:
+@@ -244,6 +245,7 @@ asn1_encode_simple_der (unsigned int etype, const unsigned char *str,
+ return ASN1_SUCCESS;
+ }
+
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /******************************************************/
+ /* Function : _asn1_time_der */
+ /* Description: creates the DER coding for a TIME */
+@@ -278,7 +280,7 @@ _asn1_time_der (unsigned char *str, int str_len, unsigned char *der,
+
+ return ASN1_SUCCESS;
+ }
+-
++#endif
+
+ /*
+ void
+@@ -519,6 +521,7 @@ asn1_bit_der (const unsigned char *str, int bit_len,
+ }
+
+
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /******************************************************/
+ /* Function : _asn1_complete_explicit_tag */
+ /* Description: add the length coding to the EXPLICIT */
+@@ -595,6 +598,7 @@ _asn1_complete_explicit_tag (asn1_node node, unsigned char *der,
+
+ return ASN1_SUCCESS;
+ }
++#endif
+
+ const tag_and_class_st _asn1_tags[] = {
+ [ASN1_ETYPE_GENERALSTRING] =
+@@ -647,6 +651,8 @@ const tag_and_class_st _asn1_tags[] = {
+
+ unsigned int _asn1_tags_size = sizeof (_asn1_tags) / sizeof (_asn1_tags[0]);
+
++
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /******************************************************/
+ /* Function : _asn1_insert_tag_der */
+ /* Description: creates the DER coding of tags of one */
+@@ -1423,3 +1429,5 @@ error:
+ asn1_delete_structure (&node);
+ return err;
+ }
++
++#endif
+diff --git a/grub-core/lib/libtasn1-grub/lib/decoding.c b/grub-core/lib/libtasn1-grub/lib/decoding.c
+index b9245c486..bf9cb13ac 100644
+--- a/grub-core/lib/libtasn1-grub/lib/decoding.c
++++ b/grub-core/lib/libtasn1-grub/lib/decoding.c
+@@ -1620,6 +1620,7 @@ asn1_der_decoding (asn1_node * element, const void *ider, int ider_len,
+ return asn1_der_decoding2 (element, ider, &ider_len, 0, errorDescription);
+ }
+
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /**
+ * asn1_der_decoding_element:
+ * @structure: pointer to an ASN1 structure
+@@ -1650,6 +1651,7 @@ asn1_der_decoding_element (asn1_node * structure, const char *elementName,
+ {
+ return asn1_der_decoding (structure, ider, len, errorDescription);
+ }
++#endif
+
+ /**
+ * asn1_der_decoding_startEnd:
+diff --git a/grub-core/lib/libtasn1-grub/lib/element.c b/grub-core/lib/libtasn1-grub/lib/element.c
+index d4c558e10..bc4c3c8d7 100644
+--- a/grub-core/lib/libtasn1-grub/lib/element.c
++++ b/grub-core/lib/libtasn1-grub/lib/element.c
+@@ -118,7 +118,7 @@ _asn1_convert_integer (const unsigned char *value, unsigned char *value_out,
+ value_out[k2 - k] = val[k2];
+ }
+
+-#if 0
++#if 0 /* GRUB SKIPPED IMPORTING */
+ printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len);
+ for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
+ printf (", vOut[%d]=%d", k, value_out[k]);
+@@ -191,7 +191,7 @@ _asn1_append_sequence_set (asn1_node node, struct node_tail_cache_st *pcache)
+ return ASN1_SUCCESS;
+ }
+
+-
++#if 0
+ /**
+ * asn1_write_value:
+ * @node_root: pointer to a structure
+@@ -646,7 +646,7 @@ asn1_write_value (asn1_node node_root, const char *name,
+
+ return ASN1_SUCCESS;
+ }
+-
++#endif
+
+ #define PUT_VALUE( ptr, ptr_size, data, data_size) \
+ *len = data_size; \
+diff --git a/grub-core/lib/libtasn1-grub/lib/errors.c b/grub-core/lib/libtasn1-grub/lib/errors.c
+index aef5dfe6f..2b2322152 100644
+--- a/grub-core/lib/libtasn1-grub/lib/errors.c
++++ b/grub-core/lib/libtasn1-grub/lib/errors.c
+@@ -57,6 +57,8 @@ static const libtasn1_error_entry error_algorithms[] = {
+ {0, 0}
+ };
+
++
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /**
+ * asn1_perror:
+ * @error: is an error returned by a libtasn1 function.
+@@ -73,6 +75,7 @@ asn1_perror (int error)
+ const char *str = asn1_strerror (error);
+ fprintf (stderr, "LIBTASN1 ERROR: %s\n", str ? str : "(null)");
+ }
++#endif
+
+ /**
+ * asn1_strerror:
+diff --git a/grub-core/lib/libtasn1-grub/lib/structure.c b/grub-core/lib/libtasn1-grub/lib/structure.c
+index 512dd601f..f5a947d57 100644
+--- a/grub-core/lib/libtasn1-grub/lib/structure.c
++++ b/grub-core/lib/libtasn1-grub/lib/structure.c
+@@ -76,7 +76,7 @@ _asn1_find_left (asn1_node_const node)
+ return node->left;
+ }
+
+-
++#if 0 /* GRUB SKIPPED IMPORTING */
+ int
+ _asn1_create_static_structure (asn1_node_const pointer,
+ char *output_file_name, char *vector_name)
+@@ -155,7 +155,7 @@ _asn1_create_static_structure (asn1_node_const pointer,
+
+ return ASN1_SUCCESS;
+ }
+-
++#endif
+
+ /**
+ * asn1_array2tree:
+@@ -721,7 +721,7 @@ asn1_create_element (asn1_node_const definitions, const char *source_name,
+ return res;
+ }
+
+-
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /**
+ * asn1_print_structure:
+ * @out: pointer to the output file (e.g. stdout).
+@@ -1062,7 +1062,7 @@ asn1_print_structure (FILE * out, asn1_node_const structure, const char *name,
+ }
+ }
+ }
+-
++#endif
+
+
+ /**
+@@ -1158,6 +1158,7 @@ asn1_find_structure_from_oid (asn1_node_const definitions,
+ return NULL; /* ASN1_ELEMENT_NOT_FOUND; */
+ }
+
++#if 0 /* GRUB SKIPPED IMPORTING */
+ /**
+ * asn1_copy_node:
+ * @dst: Destination asn1 node.
+@@ -1207,6 +1208,7 @@ asn1_copy_node (asn1_node dst, const char *dst_name,
+
+ return result;
+ }
++#endif
+
+ /**
+ * asn1_dup_node:
+diff --git a/grub-core/lib/libtasn1-grub/libtasn1.h b/grub-core/lib/libtasn1-grub/libtasn1.h
+index 51cc7879f..058ab27b0 100644
+--- a/grub-core/lib/libtasn1-grub/libtasn1.h
++++ b/grub-core/lib/libtasn1-grub/libtasn1.h
+@@ -318,6 +318,8 @@ extern "C"
+ /* Functions definitions */
+ /***********************************/
+
++/* These functions are not used in grub and should not be referenced. */
++# if 0 /* GRUB SKIPPED IMPORTING */
+ extern ASN1_API int
+ asn1_parser2tree (const char *file,
+ asn1_node * definitions, char *error_desc);
+@@ -326,14 +328,17 @@ extern "C"
+ asn1_parser2array (const char *inputFileName,
+ const char *outputFileName,
+ const char *vectorName, char *error_desc);
++# endif
+
+ extern ASN1_API int
+ asn1_array2tree (const asn1_static_node * array,
+ asn1_node * definitions, char *errorDescription);
+
++# if 0 /* GRUB SKIPPED IMPORTING */
+ extern ASN1_API void
+ asn1_print_structure (FILE * out, asn1_node_const structure,
+ const char *name, int mode);
++# endif
+
+ extern ASN1_API int
+ asn1_create_element (asn1_node_const definitions,
+@@ -347,9 +352,11 @@ extern "C"
+ extern ASN1_API int
+ asn1_delete_element (asn1_node structure, const char *element_name);
+
++# if 0 /* GRUB SKIPPED IMPORTING */
+ extern ASN1_API int
+ asn1_write_value (asn1_node node_root, const char *name,
+ const void *ivalue, int len);
++# endif
+
+ extern ASN1_API int
+ asn1_read_value (asn1_node_const root, const char *name,
+@@ -366,9 +373,11 @@ extern "C"
+ asn1_number_of_elements (asn1_node_const element, const char *name,
+ int *num);
+
++# if 0 /* GRUB SKIPPED IMPORTING */
+ extern ASN1_API int
+ asn1_der_coding (asn1_node_const element, const char *name,
+ void *ider, int *len, char *ErrorDescription);
++# endif
+
+ extern ASN1_API int
+ asn1_der_decoding2 (asn1_node * element, const void *ider,
+@@ -379,6 +388,7 @@ extern "C"
+ asn1_der_decoding (asn1_node * element, const void *ider,
+ int ider_len, char *errorDescription);
+
++# if 0 /* GRUB SKIPPED IMPORTING */
+ /* Do not use. Use asn1_der_decoding() instead. */
+ extern ASN1_API int
+ asn1_der_decoding_element (asn1_node * structure,
+@@ -386,6 +396,7 @@ extern "C"
+ const void *ider, int len,
+ char *errorDescription)
+ _ASN1_GCC_ATTR_DEPRECATED;
++# endif
+
+ extern ASN1_API int
+ asn1_der_decoding_startEnd (asn1_node element,
+@@ -411,12 +422,16 @@ extern "C"
+ const char
+ *oidValue);
+
++# if 0 /* GRUB SKIPPED IMPORTING */
+ __LIBTASN1_PURE__
+ extern ASN1_API const char *asn1_check_version (const char *req_version);
++# endif
+
+ __LIBTASN1_PURE__ extern ASN1_API const char *asn1_strerror (int error);
+
++# if 0 /* GRUB SKIPPED IMPORTING */
+ extern ASN1_API void asn1_perror (int error);
++# endif
+
+ # define ASN1_MAX_TAG_SIZE 4
+ # define ASN1_MAX_LENGTH_SIZE 9
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 04/33] libtasn1: replace strcat() with strcpy() in _asn1_str_cat()
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (2 preceding siblings ...)
2024-09-06 9:10 ` [PATCH v19 03/33] libtasn1: disable code not needed in grub Gary Lin via Grub-devel
@ 2024-09-06 9:10 ` Gary Lin via Grub-devel
2024-10-03 16:03 ` Daniel Kiper
2024-09-06 9:10 ` [PATCH v19 05/33] libtasn1: replace strcat() with _asn1_str_cat() Gary Lin via Grub-devel
` (30 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
strcat() is not available in GRUB. This commit replaces strcat() with
strcpy() in _asn1_str_cat() as the preparation to replace other strcat()
with the bounds-checking _asn1_str_cat().
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...-strcat-with-strcpy-in-_asn1_str_cat.patch | 32 +++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch
diff --git a/grub-core/lib/libtasn1-patches/0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch b/grub-core/lib/libtasn1-patches/0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch
new file mode 100644
index 000000000..18a9dd291
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch
@@ -0,0 +1,32 @@
+From 4e59e270b879693a0247011e265ccf397f19cacc Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Tue, 20 Aug 2024 16:14:51 +0800
+Subject: [PATCH 02/12] libtasn1: replace strcat() with strcpy() in
+ _asn1_str_cat()
+
+strcat() is not available in GRUB. This commit replaces strcat() with
+strcpy() in _asn1_str_cat() as the preparation to replace other strcat()
+with the bounds-checking _asn1_str_cat().
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/lib/libtasn1-grub/lib/gstr.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/lib/libtasn1-grub/lib/gstr.c b/grub-core/lib/libtasn1-grub/lib/gstr.c
+index eef419554..a9c16f5d3 100644
+--- a/grub-core/lib/libtasn1-grub/lib/gstr.c
++++ b/grub-core/lib/libtasn1-grub/lib/gstr.c
+@@ -36,7 +36,7 @@ _asn1_str_cat (char *dest, size_t dest_tot_size, const char *src)
+
+ if (dest_tot_size - dest_size > str_size)
+ {
+- strcat (dest, src);
++ strcpy (dest + dest_size, src);
+ }
+ else
+ {
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 05/33] libtasn1: replace strcat() with _asn1_str_cat()
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (3 preceding siblings ...)
2024-09-06 9:10 ` [PATCH v19 04/33] libtasn1: replace strcat() with strcpy() in _asn1_str_cat() Gary Lin via Grub-devel
@ 2024-09-06 9:10 ` Gary Lin via Grub-devel
2024-10-03 16:06 ` Daniel Kiper
2024-09-06 9:10 ` [PATCH v19 06/33] libtasn1: adjust the header paths in libtasn1.h Gary Lin via Grub-devel
` (29 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
strcat() is not available in GRUB. This commit replaces strcat() and
_asn1_strcat() with the bounds-checking _asn1_str_cat().
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...n1-replace-strcat-with-_asn1_str_cat.patch | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch
diff --git a/grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch b/grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch
new file mode 100644
index 000000000..19d86a399
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch
@@ -0,0 +1,70 @@
+From 8aa07d427966fbb560871a0a87e0af876920002c Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Tue, 20 Aug 2024 16:26:45 +0800
+Subject: [PATCH 03/12] libtasn1: replace strcat() with _asn1_str_cat()
+
+strcat() is not available in GRUB. This commit replaces strcat() and
+_asn1_strcat() with the bounds-checking _asn1_str_cat().
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/lib/libtasn1-grub/lib/decoding.c | 8 ++++----
+ grub-core/lib/libtasn1-grub/lib/element.c | 2 +-
+ grub-core/lib/libtasn1-grub/lib/int.h | 1 -
+ 3 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1-grub/lib/decoding.c b/grub-core/lib/libtasn1-grub/lib/decoding.c
+index bf9cb13ac..51859fe36 100644
+--- a/grub-core/lib/libtasn1-grub/lib/decoding.c
++++ b/grub-core/lib/libtasn1-grub/lib/decoding.c
+@@ -2016,8 +2016,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
+ (p2->type & CONST_ASSIGN))
+ {
+ strcpy (name, definitions->name);
+- strcat (name, ".");
+- strcat (name, p2->name);
++ _asn1_str_cat (name, sizeof (name), ".");
++ _asn1_str_cat (name, sizeof (name), p2->name);
+
+ len = sizeof (value);
+ result = asn1_read_value (definitions, name, value, &len);
+@@ -2034,8 +2034,8 @@ asn1_expand_octet_string (asn1_node_const definitions, asn1_node * element,
+ if (p2)
+ {
+ strcpy (name, definitions->name);
+- strcat (name, ".");
+- strcat (name, p2->name);
++ _asn1_str_cat (name, sizeof (name), ".");
++ _asn1_str_cat (name, sizeof (name), p2->name);
+
+ result = asn1_create_element (definitions, name, &aux);
+ if (result == ASN1_SUCCESS)
+diff --git a/grub-core/lib/libtasn1-grub/lib/element.c b/grub-core/lib/libtasn1-grub/lib/element.c
+index bc4c3c8d7..8694fecb9 100644
+--- a/grub-core/lib/libtasn1-grub/lib/element.c
++++ b/grub-core/lib/libtasn1-grub/lib/element.c
+@@ -688,7 +688,7 @@ asn1_write_value (asn1_node node_root, const char *name,
+ return ASN1_MEM_ERROR; \
+ } else { \
+ /* this strcat is checked */ \
+- if (ptr) _asn1_strcat (ptr, data); \
++ if (ptr) _asn1_str_cat ((char *)ptr, ptr_size, (const char *)data); \
+ }
+
+ /**
+diff --git a/grub-core/lib/libtasn1-grub/lib/int.h b/grub-core/lib/libtasn1-grub/lib/int.h
+index d94d51c8c..cadd80df6 100644
+--- a/grub-core/lib/libtasn1-grub/lib/int.h
++++ b/grub-core/lib/libtasn1-grub/lib/int.h
+@@ -115,7 +115,6 @@ extern const tag_and_class_st _asn1_tags[];
+ # define _asn1_strtoul(n,e,b) strtoul((const char *) n, e, b)
+ # define _asn1_strcmp(a,b) strcmp((const char *)a, (const char *)b)
+ # define _asn1_strcpy(a,b) strcpy((char *)a, (const char *)b)
+-# define _asn1_strcat(a,b) strcat((char *)a, (const char *)b)
+
+ # if SIZEOF_UNSIGNED_LONG_INT == 8
+ # define _asn1_strtou64(n,e,b) strtoul((const char *) n, e, b)
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 06/33] libtasn1: adjust the header paths in libtasn1.h
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (4 preceding siblings ...)
2024-09-06 9:10 ` [PATCH v19 05/33] libtasn1: replace strcat() with _asn1_str_cat() Gary Lin via Grub-devel
@ 2024-09-06 9:10 ` Gary Lin via Grub-devel
2024-10-03 16:08 ` Daniel Kiper
2024-09-06 9:10 ` [PATCH v19 07/33] libtasn1: Use grub_divmod64() for division Gary Lin via Grub-devel
` (28 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
Since libtasn1.h is the header to be included by users, including the
standard POSIX headers in libtasn1.h would force the user to add the
CFLAGS/CPPFLAGS for the POSIX headers.
This commit adjusts the header paths to use the grub headers instead of
the standard POSIX headers, so that users only need to include
libtasn1.h to use libtasn1 functions.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
| 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch
--git a/grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch b/grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch
new file mode 100644
index 000000000..592007b97
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch
@@ -0,0 +1,38 @@
+From 3ea2376db98e99a4461411fc476850de33822999 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Tue, 25 Jun 2024 16:30:40 +0800
+Subject: [PATCH 04/12] libtasn1: adjust the header paths in libtasn1.h
+
+Since libtasn1.h is the header to be included by users, including the
+standard POSIX headers in libtasn1.h would force the user to add the
+CFLAGS/CPPFLAGS for the POSIX headers.
+
+This commit adjusts the header paths to use the grub headers instead of
+the standard POSIX headers, so that users only need to include
+libtasn1.h to use libtasn1 functions.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/lib/libtasn1-grub/libtasn1.h | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/grub-core/lib/libtasn1-grub/libtasn1.h b/grub-core/lib/libtasn1-grub/libtasn1.h
+index 058ab27b0..7d64b6ab7 100644
+--- a/grub-core/lib/libtasn1-grub/libtasn1.h
++++ b/grub-core/lib/libtasn1-grub/libtasn1.h
+@@ -54,9 +54,8 @@
+ # define __LIBTASN1_PURE__
+ # endif
+
+-# include <sys/types.h>
+-# include <time.h>
+-# include <stdio.h> /* for FILE* */
++# include <grub/types.h>
++# include <grub/time.h>
+
+ # ifdef __cplusplus
+ extern "C"
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 07/33] libtasn1: Use grub_divmod64() for division
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (5 preceding siblings ...)
2024-09-06 9:10 ` [PATCH v19 06/33] libtasn1: adjust the header paths in libtasn1.h Gary Lin via Grub-devel
@ 2024-09-06 9:10 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 08/33] libtasn1: fix the potential buffer overrun Gary Lin via Grub-devel
` (27 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:10 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
Replace a 64-bit division with a call to grub_divmod64(), preventing
creation of __udivdi3() calls on 32-bit platforms.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
...tasn1-Use-grub_divmod64-for-division.patch | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch
diff --git a/grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch b/grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch
new file mode 100644
index 000000000..5cd64bb45
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0005-libtasn1-Use-grub_divmod64-for-division.patch
@@ -0,0 +1,31 @@
+From f4d086cc829544a33fd6fd705538cd8d820d6c40 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Tue, 25 Jun 2024 16:32:50 +0800
+Subject: [PATCH 05/12] libtasn1: Use grub_divmod64() for division
+
+Replace a 64-bit division with a call to grub_divmod64(), preventing
+creation of __udivdi3() calls on 32-bit platforms.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/lib/libtasn1-grub/lib/parser_aux.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/lib/libtasn1-grub/lib/parser_aux.c b/grub-core/lib/libtasn1-grub/lib/parser_aux.c
+index c05bd2339..e4e4c0556 100644
+--- a/grub-core/lib/libtasn1-grub/lib/parser_aux.c
++++ b/grub-core/lib/libtasn1-grub/lib/parser_aux.c
+@@ -632,7 +632,7 @@ _asn1_ltostr (int64_t v, char str[LTOSTR_MAX_SIZE])
+ count = 0;
+ do
+ {
+- d = val / 10;
++ d = grub_divmod64(val, 10, NULL);
+ r = val - d * 10;
+ temp[start + count] = '0' + (char) r;
+ count++;
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 08/33] libtasn1: fix the potential buffer overrun
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (6 preceding siblings ...)
2024-09-06 9:10 ` [PATCH v19 07/33] libtasn1: Use grub_divmod64() for division Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 09/33] asn1_test: include asn1_test.h only Gary Lin via Grub-devel
` (26 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
In _asn1_tag_der(), the first while loop for the long form may end up
with a 'k' value with 'ASN1_MAX_TAG_SIZE' and cause the buffer overrun
in the second while loop. This commit tweaks the conditional check to
avoid producing a too large 'k'.
This is a quick fix and may differ from the official upstream fix.
libtasn1 issue: https://gitlab.com/gnutls/libtasn1/-/issues/49
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
...sn1-fix-the-potential-buffer-overrun.patch | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch
diff --git a/grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch b/grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch
new file mode 100644
index 000000000..c7c995565
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0006-libtasn1-fix-the-potential-buffer-overrun.patch
@@ -0,0 +1,36 @@
+From 66f5485a9b4ea02f7d2796c5f245fcbf7c88b390 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Mon, 8 Apr 2024 14:57:21 +0800
+Subject: [PATCH 06/12] libtasn1: fix the potential buffer overrun
+
+In _asn1_tag_der(), the first while loop for the long form may end up
+with a 'k' value with 'ASN1_MAX_TAG_SIZE' and cause the buffer overrun
+in the second while loop. This commit tweaks the conditional check to
+avoid producing a too large 'k'.
+
+This is a quick fix and may differ from the official upstream fix.
+
+libtasn1 issue: https://gitlab.com/gnutls/libtasn1/-/issues/49
+
+Signed-off-by: Gary Lin <glin@suse.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+ grub-core/lib/libtasn1-grub/lib/coding.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/grub-core/lib/libtasn1-grub/lib/coding.c b/grub-core/lib/libtasn1-grub/lib/coding.c
+index 5d03bca9d..0458829a5 100644
+--- a/grub-core/lib/libtasn1-grub/lib/coding.c
++++ b/grub-core/lib/libtasn1-grub/lib/coding.c
+@@ -143,7 +143,7 @@ _asn1_tag_der (unsigned char class, unsigned int tag_value,
+ temp[k++] = tag_value & 0x7F;
+ tag_value >>= 7;
+
+- if (k > ASN1_MAX_TAG_SIZE - 1)
++ if (k >= ASN1_MAX_TAG_SIZE - 1)
+ break; /* will not encode larger tags */
+ }
+ *ans_len = k + 1;
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 09/33] asn1_test: include asn1_test.h only
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (7 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 08/33] libtasn1: fix the potential buffer overrun Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-04 15:38 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 10/33] asn1_test: rename the main functions to the test names Gary Lin via Grub-devel
` (25 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
This commit removes all the headers and only uses asn1_test.h.
To avoid including int.h from grub-core/lib/libtasn1-grub/lib/,
CONST_DOWN is defined in reproducers.c.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...7-asn1_test-include-asn1_test.h-only.patch | 163 ++++++++++++++++++
1 file changed, 163 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0007-asn1_test-include-asn1_test.h-only.patch
diff --git a/grub-core/lib/libtasn1-patches/0007-asn1_test-include-asn1_test.h-only.patch b/grub-core/lib/libtasn1-patches/0007-asn1_test-include-asn1_test.h-only.patch
new file mode 100644
index 000000000..8780b0784
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0007-asn1_test-include-asn1_test.h-only.patch
@@ -0,0 +1,163 @@
+From f1fef1a65ff5ba39f78230f8b4f663bb8f5884b7 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Fri, 16 Aug 2024 14:10:21 +0800
+Subject: [PATCH 07/12] asn1_test: include asn1_test.h only
+
+This commit removes all the headers and only uses asn1_test.h.
+To avoid including int.h from grub-core/lib/libtasn1-grub/lib/,
+CONST_DOWN is defined in reproducers.c.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/tests/asn1/tests/CVE-2018-1000654.c | 4 +---
+ grub-core/tests/asn1/tests/Test_overflow.c | 7 +------
+ grub-core/tests/asn1/tests/Test_simple.c | 6 +-----
+ grub-core/tests/asn1/tests/Test_strings.c | 6 +-----
+ grub-core/tests/asn1/tests/object-id-decoding.c | 6 +-----
+ grub-core/tests/asn1/tests/object-id-encoding.c | 6 +-----
+ grub-core/tests/asn1/tests/octet-string.c | 6 +-----
+ grub-core/tests/asn1/tests/reproducers.c | 8 ++------
+ 8 files changed, 9 insertions(+), 40 deletions(-)
+
+diff --git a/grub-core/tests/asn1/tests/CVE-2018-1000654.c b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+index 0c22b7012..98c2a8b8c 100644
+--- a/grub-core/tests/asn1/tests/CVE-2018-1000654.c
++++ b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+@@ -22,9 +22,7 @@
+ /* Description: reproducer for CVE-2018-1000654 */
+ /****************************************************************/
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
++#include "asn1_test.h"
+ #include "CVE-2018-1000654-1_asn1_tab.h"
+ #include "CVE-2018-1000654-2_asn1_tab.h"
+
+diff --git a/grub-core/tests/asn1/tests/Test_overflow.c b/grub-core/tests/asn1/tests/Test_overflow.c
+index c61dea4bb..73e9d8c68 100644
+--- a/grub-core/tests/asn1/tests/Test_overflow.c
++++ b/grub-core/tests/asn1/tests/Test_overflow.c
+@@ -20,12 +20,7 @@
+
+ /* Written by Simon Josefsson */
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-#include <limits.h>
+-
+-#include "libtasn1.h"
++#include "asn1_test.h"
+
+ int
+ main (int argc, char **argv)
+diff --git a/grub-core/tests/asn1/tests/Test_simple.c b/grub-core/tests/asn1/tests/Test_simple.c
+index 6cd07e069..3aa8ce21b 100644
+--- a/grub-core/tests/asn1/tests/Test_simple.c
++++ b/grub-core/tests/asn1/tests/Test_simple.c
+@@ -20,11 +20,7 @@
+ *
+ */
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-
+-#include "libtasn1.h"
++#include "asn1_test.h"
+
+ struct tv
+ {
+diff --git a/grub-core/tests/asn1/tests/Test_strings.c b/grub-core/tests/asn1/tests/Test_strings.c
+index 27f7215e1..c49229af9 100644
+--- a/grub-core/tests/asn1/tests/Test_strings.c
++++ b/grub-core/tests/asn1/tests/Test_strings.c
+@@ -20,11 +20,7 @@
+ *
+ */
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-
+-#include "libtasn1.h"
++#include "asn1_test.h"
+
+ struct tv
+ {
+diff --git a/grub-core/tests/asn1/tests/object-id-decoding.c b/grub-core/tests/asn1/tests/object-id-decoding.c
+index 06a6c52a2..0a77db752 100644
+--- a/grub-core/tests/asn1/tests/object-id-decoding.c
++++ b/grub-core/tests/asn1/tests/object-id-decoding.c
+@@ -18,11 +18,7 @@
+ *
+ */
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-
+-#include "libtasn1.h"
++#include "asn1_test.h"
+
+ struct tv
+ {
+diff --git a/grub-core/tests/asn1/tests/object-id-encoding.c b/grub-core/tests/asn1/tests/object-id-encoding.c
+index 1a3396986..e32835830 100644
+--- a/grub-core/tests/asn1/tests/object-id-encoding.c
++++ b/grub-core/tests/asn1/tests/object-id-encoding.c
+@@ -18,11 +18,7 @@
+ *
+ */
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-
+-#include "libtasn1.h"
++#include "asn1_test.h"
+
+ struct tv
+ {
+diff --git a/grub-core/tests/asn1/tests/octet-string.c b/grub-core/tests/asn1/tests/octet-string.c
+index 69eb18a62..8e803af41 100644
+--- a/grub-core/tests/asn1/tests/octet-string.c
++++ b/grub-core/tests/asn1/tests/octet-string.c
+@@ -20,11 +20,7 @@
+ *
+ */
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
+-
+-#include "libtasn1.h"
++#include "asn1_test.h"
+
+ struct tv
+ {
+diff --git a/grub-core/tests/asn1/tests/reproducers.c b/grub-core/tests/asn1/tests/reproducers.c
+index a09d8b021..ce24e0991 100644
+--- a/grub-core/tests/asn1/tests/reproducers.c
++++ b/grub-core/tests/asn1/tests/reproducers.c
+@@ -22,13 +22,9 @@
+ /* Description: run reproducers for several fixed issues */
+ /****************************************************************/
+
+-#include <stdio.h>
+-#include <string.h>
+-#include <stdlib.h>
++#include "asn1_test.h"
+
+-#include <libtasn1.h>
+-
+-#include <int.h>
++#define CONST_DOWN (1U<<29)
+
+ /* produces endless loop (fixed by d4b624b2):
+ * The following translates into a single node with all pointers
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 10/33] asn1_test: rename the main functions to the test names
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (8 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 09/33] asn1_test: include asn1_test.h only Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-04 15:43 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 11/33] asn1_test: remove 'verbose' and the unnecessary printf() Gary Lin via Grub-devel
` (24 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
This commit changes the main functions in the testcases to the test
names so that the real 'main' test function can invokes them.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...-the-main-functions-to-the-test-name.patch | 128 ++++++++++++++++++
1 file changed, 128 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0008-asn1_test-rename-the-main-functions-to-the-test-name.patch
diff --git a/grub-core/lib/libtasn1-patches/0008-asn1_test-rename-the-main-functions-to-the-test-name.patch b/grub-core/lib/libtasn1-patches/0008-asn1_test-rename-the-main-functions-to-the-test-name.patch
new file mode 100644
index 000000000..3940e4e9e
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0008-asn1_test-rename-the-main-functions-to-the-test-name.patch
@@ -0,0 +1,128 @@
+From 5d1f9b5fd4df3f62ad20cbbecd3865c033aad7a2 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Fri, 16 Aug 2024 14:18:44 +0800
+Subject: [PATCH 08/12] asn1_test: rename the main functions to the test names
+
+This commit changes the main functions in the testcases to the test
+names so that the real 'main' test function can invokes them.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/tests/asn1/tests/CVE-2018-1000654.c | 2 +-
+ grub-core/tests/asn1/tests/Test_overflow.c | 2 +-
+ grub-core/tests/asn1/tests/Test_simple.c | 2 +-
+ grub-core/tests/asn1/tests/Test_strings.c | 2 +-
+ grub-core/tests/asn1/tests/object-id-decoding.c | 2 +-
+ grub-core/tests/asn1/tests/object-id-encoding.c | 2 +-
+ grub-core/tests/asn1/tests/octet-string.c | 2 +-
+ grub-core/tests/asn1/tests/reproducers.c | 2 +-
+ 8 files changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/grub-core/tests/asn1/tests/CVE-2018-1000654.c b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+index 98c2a8b8c..a935ab541 100644
+--- a/grub-core/tests/asn1/tests/CVE-2018-1000654.c
++++ b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+@@ -27,7 +27,7 @@
+ #include "CVE-2018-1000654-2_asn1_tab.h"
+
+ int
+-main (int argc, char *argv[])
++test_CVE_2018_1000654 (void)
+ {
+ int result, verbose = 0;
+ asn1_node definitions = NULL;
+diff --git a/grub-core/tests/asn1/tests/Test_overflow.c b/grub-core/tests/asn1/tests/Test_overflow.c
+index 73e9d8c68..bc28d0826 100644
+--- a/grub-core/tests/asn1/tests/Test_overflow.c
++++ b/grub-core/tests/asn1/tests/Test_overflow.c
+@@ -23,7 +23,7 @@
+ #include "asn1_test.h"
+
+ int
+-main (int argc, char **argv)
++test_overflow (void)
+ {
+ /* Test that values larger than long are rejected. This has worked
+ fine with all versions of libtasn1. */
+diff --git a/grub-core/tests/asn1/tests/Test_simple.c b/grub-core/tests/asn1/tests/Test_simple.c
+index 3aa8ce21b..12993bfba 100644
+--- a/grub-core/tests/asn1/tests/Test_simple.c
++++ b/grub-core/tests/asn1/tests/Test_simple.c
+@@ -73,7 +73,7 @@ static const struct tv tv[] = {
+ };
+
+ int
+-main (int argc, char *argv[])
++test_simple (void)
+ {
+ int result;
+ unsigned char der[100];
+diff --git a/grub-core/tests/asn1/tests/Test_strings.c b/grub-core/tests/asn1/tests/Test_strings.c
+index c49229af9..2538f2558 100644
+--- a/grub-core/tests/asn1/tests/Test_strings.c
++++ b/grub-core/tests/asn1/tests/Test_strings.c
+@@ -70,7 +70,7 @@ static const struct tv ber[] = {
+ };
+
+ int
+-main (int argc, char *argv[])
++test_strings (void)
+ {
+ int ret;
+ unsigned char tl[ASN1_MAX_TL_SIZE];
+diff --git a/grub-core/tests/asn1/tests/object-id-decoding.c b/grub-core/tests/asn1/tests/object-id-decoding.c
+index 0a77db752..fdbb8ea21 100644
+--- a/grub-core/tests/asn1/tests/object-id-decoding.c
++++ b/grub-core/tests/asn1/tests/object-id-decoding.c
+@@ -70,7 +70,7 @@ static const struct tv tv[] = {
+ };
+
+ int
+-main (int argc, char *argv[])
++test_object_id_decoding (void)
+ {
+ char str[128];
+ int ret, ret_len;
+diff --git a/grub-core/tests/asn1/tests/object-id-encoding.c b/grub-core/tests/asn1/tests/object-id-encoding.c
+index e32835830..a497015e3 100644
+--- a/grub-core/tests/asn1/tests/object-id-encoding.c
++++ b/grub-core/tests/asn1/tests/object-id-encoding.c
+@@ -80,7 +80,7 @@ static const struct tv tv[] = {
+ };
+
+ int
+-main (int argc, char *argv[])
++test_object_id_encoding (void)
+ {
+ unsigned char der[128];
+ int ret, der_len, i, j;
+diff --git a/grub-core/tests/asn1/tests/octet-string.c b/grub-core/tests/asn1/tests/octet-string.c
+index 8e803af41..8c49c6e0c 100644
+--- a/grub-core/tests/asn1/tests/octet-string.c
++++ b/grub-core/tests/asn1/tests/octet-string.c
+@@ -108,7 +108,7 @@ static const struct tv tv[] = {
+ };
+
+ int
+-main (int argc, char *argv[])
++test_octet_string (void)
+ {
+ unsigned char str[100];
+ unsigned char der[100];
+diff --git a/grub-core/tests/asn1/tests/reproducers.c b/grub-core/tests/asn1/tests/reproducers.c
+index ce24e0991..e843b74b9 100644
+--- a/grub-core/tests/asn1/tests/reproducers.c
++++ b/grub-core/tests/asn1/tests/reproducers.c
+@@ -49,7 +49,7 @@ const asn1_static_node tab[] = {
+ };
+
+ int
+-main (int argc, char *argv[])
++test_reproducers (void)
+ {
+ int result, verbose = 0;
+ asn1_node definitions = NULL;
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 11/33] asn1_test: remove 'verbose' and the unnecessary printf()
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (9 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 10/33] asn1_test: rename the main functions to the test names Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-04 16:28 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 12/33] asn1_test: print the error messages with grub_printf() Gary Lin via Grub-devel
` (23 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
This commit removes the 'verbose' variables and the unnecessary printf()
to simplify the output.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...e-verbose-and-the-unnecessary-printf.patch | 172 ++++++++++++++++++
1 file changed, 172 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0009-asn1_test-remove-verbose-and-the-unnecessary-printf.patch
diff --git a/grub-core/lib/libtasn1-patches/0009-asn1_test-remove-verbose-and-the-unnecessary-printf.patch b/grub-core/lib/libtasn1-patches/0009-asn1_test-remove-verbose-and-the-unnecessary-printf.patch
new file mode 100644
index 000000000..f73de240c
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0009-asn1_test-remove-verbose-and-the-unnecessary-printf.patch
@@ -0,0 +1,172 @@
+From 408ccf080a5d0993aac217639ac0b8cfe34e0cf6 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Fri, 16 Aug 2024 14:26:38 +0800
+Subject: [PATCH 09/12] asn1_test: remove 'verbose' and the unnecessary
+ printf()
+
+This commit removes the 'verbose' variables and the unnecessary printf()
+to simplify the output.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/tests/asn1/tests/CVE-2018-1000654.c | 11 +----
+ grub-core/tests/asn1/tests/Test_overflow.c | 40 +++----------------
+ grub-core/tests/asn1/tests/reproducers.c | 8 +---
+ 3 files changed, 7 insertions(+), 52 deletions(-)
+
+diff --git a/grub-core/tests/asn1/tests/CVE-2018-1000654.c b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+index a935ab541..5710b61a7 100644
+--- a/grub-core/tests/asn1/tests/CVE-2018-1000654.c
++++ b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+@@ -29,15 +29,10 @@
+ int
+ test_CVE_2018_1000654 (void)
+ {
+- int result, verbose = 0;
++ int result;
+ asn1_node definitions = NULL;
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+
+- if (argc > 1)
+- verbose = 1;
+-
+- printf ("Test 1\n");
+-
+ result =
+ asn1_array2tree (CVE_2018_1000654_1_asn1_tab, &definitions,
+ errorDescription);
+@@ -50,8 +45,6 @@ test_CVE_2018_1000654 (void)
+
+ asn1_delete_structure (&definitions);
+
+- printf ("Test 2\n");
+-
+ result =
+ asn1_array2tree (CVE_2018_1000654_2_asn1_tab, &definitions,
+ errorDescription);
+@@ -64,7 +57,5 @@ test_CVE_2018_1000654 (void)
+
+ asn1_delete_structure (&definitions);
+
+- if (verbose)
+- printf ("Success\n");
+ exit (0);
+ }
+diff --git a/grub-core/tests/asn1/tests/Test_overflow.c b/grub-core/tests/asn1/tests/Test_overflow.c
+index bc28d0826..9f9578a1f 100644
+--- a/grub-core/tests/asn1/tests/Test_overflow.c
++++ b/grub-core/tests/asn1/tests/Test_overflow.c
+@@ -27,11 +27,6 @@ test_overflow (void)
+ {
+ /* Test that values larger than long are rejected. This has worked
+ fine with all versions of libtasn1. */
+- int verbose = 0;
+-
+- if (argc > 1)
+- verbose = 1;
+-
+ {
+ unsigned char der[] = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
+ long l;
+@@ -39,12 +34,7 @@ test_overflow (void)
+
+ l = asn1_get_length_der (der, sizeof der, &len);
+
+- if (l == -2L)
+- {
+- if (verbose)
+- puts ("OK: asn1_get_length_der bignum");
+- }
+- else
++ if (l != -2L)
+ {
+ printf ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
+ return 1;
+@@ -65,12 +55,7 @@ test_overflow (void)
+
+ l = asn1_get_length_der (der, der_len, &len);
+
+- if (l == -2L)
+- {
+- if (verbose)
+- puts ("OK: asn1_get_length_der intnum");
+- }
+- else
++ if (l != -2L)
+ {
+ printf ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l,
+ len);
+@@ -92,12 +77,7 @@ test_overflow (void)
+ der_len = sizeof (der);
+ l = asn1_get_length_der (der, der_len, &len);
+
+- if (l == -4L)
+- {
+- if (verbose)
+- puts ("OK: asn1_get_length_der overflow-small");
+- }
+- else
++ if (l != -4L)
+ {
+ printf ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n",
+ l, len);
+@@ -119,12 +99,7 @@ test_overflow (void)
+ der_len = sizeof (der);
+ l = asn1_get_length_der (der, der_len, &len);
+
+- if (l == -4L)
+- {
+- if (verbose)
+- puts ("OK: asn1_get_length_der overflow-large1");
+- }
+- else
++ if (l != -4L)
+ {
+ printf ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n",
+ l, len);
+@@ -146,12 +121,7 @@ test_overflow (void)
+ der_len = sizeof (der);
+ l = asn1_get_length_der (der, der_len, &len);
+
+- if (l == -2L)
+- {
+- if (verbose)
+- puts ("OK: asn1_get_length_der overflow-large2");
+- }
+- else
++ if (l != -2L)
+ {
+ printf ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n",
+ l, len);
+diff --git a/grub-core/tests/asn1/tests/reproducers.c b/grub-core/tests/asn1/tests/reproducers.c
+index e843b74b9..d68fc0fbd 100644
+--- a/grub-core/tests/asn1/tests/reproducers.c
++++ b/grub-core/tests/asn1/tests/reproducers.c
+@@ -51,13 +51,10 @@ const asn1_static_node tab[] = {
+ int
+ test_reproducers (void)
+ {
+- int result, verbose = 0;
++ int result;
+ asn1_node definitions = NULL;
+ char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
+
+- if (argc > 1)
+- verbose = 1;
+-
+ result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription);
+ if (result != ASN1_SUCCESS)
+ {
+@@ -79,8 +76,5 @@ test_reproducers (void)
+
+ asn1_delete_structure (&definitions);
+
+- if (verbose)
+- printf ("Success\n");
+-
+ exit (EXIT_SUCCESS);
+ }
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 12/33] asn1_test: print the error messages with grub_printf()
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (10 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 11/33] asn1_test: remove 'verbose' and the unnecessary printf() Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-04 16:31 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 13/33] asn1_test: return either 0 or 1 to reflect the results Gary Lin via Grub-devel
` (22 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
This commit replaces printf() and fprintf() with grub_printf() to print
the error messages for the testcases. Besides, asn1_strerror() is used
to convert the result code to strings instead of asn1_perror().
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...-the-error-messages-with-grub_printf.patch | 484 ++++++++++++++++++
1 file changed, 484 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0010-asn1_test-print-the-error-messages-with-grub_printf.patch
diff --git a/grub-core/lib/libtasn1-patches/0010-asn1_test-print-the-error-messages-with-grub_printf.patch b/grub-core/lib/libtasn1-patches/0010-asn1_test-print-the-error-messages-with-grub_printf.patch
new file mode 100644
index 000000000..b6d057d45
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0010-asn1_test-print-the-error-messages-with-grub_printf.patch
@@ -0,0 +1,484 @@
+From 2bc1bdd99f43da96305add2ce591ca637dce5648 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Fri, 16 Aug 2024 15:00:42 +0800
+Subject: [PATCH 10/12] asn1_test: print the error messages with grub_printf()
+
+This commit replaces printf() and fprintf() with grub_printf() to print
+the error messages for the testcases. Besides, asn1_strerror() is used
+to convert the result code to strings instead of asn1_perror().
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/tests/asn1/tests/CVE-2018-1000654.c | 8 +--
+ grub-core/tests/asn1/tests/Test_overflow.c | 14 ++---
+ grub-core/tests/asn1/tests/Test_simple.c | 21 ++++----
+ grub-core/tests/asn1/tests/Test_strings.c | 21 +++-----
+ .../tests/asn1/tests/object-id-decoding.c | 16 +++---
+ .../tests/asn1/tests/object-id-encoding.c | 26 ++++-----
+ grub-core/tests/asn1/tests/octet-string.c | 54 ++++++++-----------
+ grub-core/tests/asn1/tests/reproducers.c | 6 +--
+ 8 files changed, 67 insertions(+), 99 deletions(-)
+
+diff --git a/grub-core/tests/asn1/tests/CVE-2018-1000654.c b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+index 5710b61a7..9eb4d7979 100644
+--- a/grub-core/tests/asn1/tests/CVE-2018-1000654.c
++++ b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+@@ -38,8 +38,8 @@ test_CVE_2018_1000654 (void)
+ errorDescription);
+ if (result != ASN1_RECURSION)
+ {
+- asn1_perror (result);
+- printf ("ErrorDescription = %s\n\n", errorDescription);
++ grub_printf ("Error: %s\nErrorDescription = %s\n\n",
++ asn1_strerror (result), errorDescription);
+ exit (1);
+ }
+
+@@ -50,8 +50,8 @@ test_CVE_2018_1000654 (void)
+ errorDescription);
+ if (result != ASN1_RECURSION)
+ {
+- asn1_perror (result);
+- printf ("ErrorDescription = %s\n\n", errorDescription);
++ grub_printf ("Error: %s\nErrorDescription = %s\n\n",
++ asn1_strerror (result), errorDescription);
+ exit (1);
+ }
+
+diff --git a/grub-core/tests/asn1/tests/Test_overflow.c b/grub-core/tests/asn1/tests/Test_overflow.c
+index 9f9578a1f..ffac8507a 100644
+--- a/grub-core/tests/asn1/tests/Test_overflow.c
++++ b/grub-core/tests/asn1/tests/Test_overflow.c
+@@ -36,7 +36,7 @@ test_overflow (void)
+
+ if (l != -2L)
+ {
+- printf ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
++ grub_printf ("ERROR: asn1_get_length_der bignum (l %ld len %d)\n", l, len);
+ return 1;
+ }
+ }
+@@ -57,8 +57,7 @@ test_overflow (void)
+
+ if (l != -2L)
+ {
+- printf ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l,
+- len);
++ grub_printf ("ERROR: asn1_get_length_der intnum (l %ld len %d)\n", l, len);
+ return 1;
+ }
+ }
+@@ -79,8 +78,7 @@ test_overflow (void)
+
+ if (l != -4L)
+ {
+- printf ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n",
+- l, len);
++ grub_printf ("ERROR: asn1_get_length_der overflow-small (l %ld len %d)\n", l, len);
+ return 1;
+ }
+ }
+@@ -101,8 +99,7 @@ test_overflow (void)
+
+ if (l != -4L)
+ {
+- printf ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n",
+- l, len);
++ grub_printf ("ERROR: asn1_get_length_der overflow-large1 (l %ld len %d)\n", l, len);
+ return 1;
+ }
+ }
+@@ -123,8 +120,7 @@ test_overflow (void)
+
+ if (l != -2L)
+ {
+- printf ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n",
+- l, len);
++ grub_printf ("ERROR: asn1_get_length_der overflow-large2 (l %ld len %d)\n", l, len);
+ return 1;
+ }
+ }
+diff --git a/grub-core/tests/asn1/tests/Test_simple.c b/grub-core/tests/asn1/tests/Test_simple.c
+index 12993bfba..dc70db191 100644
+--- a/grub-core/tests/asn1/tests/Test_simple.c
++++ b/grub-core/tests/asn1/tests/Test_simple.c
+@@ -94,7 +94,7 @@ test_simple (void)
+ result = asn1_encode_simple_der (etype, my_str, my_str_len, tl, &tl_len);
+ if (result != ASN1_VALUE_NOT_VALID)
+ {
+- fprintf (stderr, "asn1_encode_simple_der out of range etype\n");
++ grub_printf ("asn1_encode_simple_der out of range etype\n");
+ return 1;
+ }
+ }
+@@ -105,7 +105,7 @@ test_simple (void)
+ result = asn1_get_bit_der (der, 0, &ret_len, str, str_size, &bit_len);
+ if (result != ASN1_GENERIC_ERROR)
+ {
+- fprintf (stderr, "asn1_get_bit_der zero\n");
++ grub_printf ("asn1_get_bit_der zero\n");
+ return 1;
+ }
+
+@@ -129,7 +129,7 @@ test_simple (void)
+
+ if (der_len != tv[i].derlen || memcmp (der, tv[i].der, der_len) != 0)
+ {
+- fprintf (stderr, "asn1_bit_der iter %lu\n", (unsigned long) i);
++ grub_printf ("asn1_bit_der iter %lu\n", (unsigned long) i);
+ return 1;
+ }
+
+@@ -140,8 +140,7 @@ test_simple (void)
+ if (result != ASN1_SUCCESS || ret_len != tv[i].derlen
+ || bit_len != tv[i].bitlen)
+ {
+- fprintf (stderr, "asn1_get_bit_der iter %lu, err: %d\n",
+- (unsigned long) i, result);
++ grub_printf ("asn1_get_bit_der iter %lu, err: %d\n", (unsigned long) i, result);
+ return 1;
+ }
+ }
+@@ -163,7 +162,7 @@ test_simple (void)
+ if (result != ASN1_SUCCESS || ret_len != 5
+ || bit_len != 18 || memcmp (str, "\x6e\x5d\xc0", 3) != 0)
+ {
+- fprintf (stderr, "asn1_get_bit_der example\n");
++ grub_printf ("asn1_get_bit_der example\n");
+ return 1;
+ }
+
+@@ -171,7 +170,7 @@ test_simple (void)
+ asn1_bit_der (str, bit_len, der, &der_len);
+ if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+- fprintf (stderr, "asn1_bit_der example roundtrip\n");
++ grub_printf ("asn1_bit_der example roundtrip\n");
+ return 1;
+ }
+
+@@ -184,7 +183,7 @@ test_simple (void)
+ if (result != ASN1_SUCCESS || ret_len != 5
+ || bit_len != 18 || memcmp (str, "\x6e\x5d\xe0", 3) != 0)
+ {
+- fprintf (stderr, "asn1_get_bit_der example padded\n");
++ grub_printf ("asn1_get_bit_der example padded\n");
+ return 1;
+ }
+
+@@ -192,7 +191,7 @@ test_simple (void)
+ asn1_bit_der (str, bit_len, der, &der_len);
+ if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+- fprintf (stderr, "asn1_bit_der example roundtrip\n");
++ grub_printf ("asn1_bit_der example roundtrip\n");
+ return 1;
+ }
+
+@@ -206,7 +205,7 @@ test_simple (void)
+ if (result != ASN1_SUCCESS || ret_len != 6
+ || bit_len != 18 || memcmp (str, "\x6e\x5d\xc0", 3) != 0)
+ {
+- fprintf (stderr, "asn1_get_bit_der example long form\n");
++ grub_printf ("asn1_get_bit_der example long form\n");
+ return 1;
+ }
+
+@@ -214,7 +213,7 @@ test_simple (void)
+ asn1_bit_der (str, bit_len, der, &der_len);
+ if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+- fprintf (stderr, "asn1_bit_der example roundtrip\n");
++ grub_printf ("asn1_bit_der example roundtrip\n");
+ return 1;
+ }
+
+diff --git a/grub-core/tests/asn1/tests/Test_strings.c b/grub-core/tests/asn1/tests/Test_strings.c
+index 2538f2558..65c30937f 100644
+--- a/grub-core/tests/asn1/tests/Test_strings.c
++++ b/grub-core/tests/asn1/tests/Test_strings.c
+@@ -89,17 +89,14 @@ test_strings (void)
+ tl, &tl_len);
+ if (ret != ASN1_SUCCESS)
+ {
+- fprintf (stderr, "Encoding error in %u: %s\n", i,
+- asn1_strerror (ret));
++ grub_printf ("Encoding error in %u: %s\n", i, asn1_strerror (ret));
+ return 1;
+ }
+ der_len = tl_len + tv[i].str_len;
+
+ if (der_len != tv[i].der_len || memcmp (tl, tv[i].der, tl_len) != 0)
+ {
+- fprintf (stderr,
+- "DER encoding differs in %u! (size: %u, expected: %u)\n",
+- i, der_len, tv[i].der_len);
++ grub_printf ("DER encoding differs in %u! (size: %u, expected: %u)\n", i, der_len, tv[i].der_len);
+ return 1;
+ }
+
+@@ -109,16 +106,13 @@ test_strings (void)
+ &str_len);
+ if (ret != ASN1_SUCCESS)
+ {
+- fprintf (stderr, "Decoding error in %u: %s\n", i,
+- asn1_strerror (ret));
++ grub_printf ("Decoding error in %u: %s\n", i, asn1_strerror (ret));
+ return 1;
+ }
+
+ if (str_len != tv[i].str_len || memcmp (str, tv[i].str, str_len) != 0)
+ {
+- fprintf (stderr,
+- "DER decoded data differ in %u! (size: %u, expected: %u)\n",
+- i, der_len, tv[i].str_len);
++ grub_printf ("DER decoded data differ in %u! (size: %u, expected: %u)\n", i, der_len, tv[i].str_len);
+ return 1;
+ }
+ }
+@@ -132,16 +126,13 @@ test_strings (void)
+ &str_len, NULL);
+ if (ret != ASN1_SUCCESS)
+ {
+- fprintf (stderr, "BER decoding error in %u: %s\n", i,
+- asn1_strerror (ret));
++ grub_printf ("BER decoding error in %u: %s\n", i, asn1_strerror (ret));
+ return 1;
+ }
+
+ if (str_len != ber[i].str_len || memcmp (b, ber[i].str, str_len) != 0)
+ {
+- fprintf (stderr,
+- "BER decoded data differ in %u! (size: %u, expected: %u)\n",
+- i, str_len, ber[i].str_len);
++ grub_printf ("BER decoded data differ in %u! (size: %u, expected: %u)\n", i, str_len, ber[i].str_len);
+ return 1;
+ }
+ free (b);
+diff --git a/grub-core/tests/asn1/tests/object-id-decoding.c b/grub-core/tests/asn1/tests/object-id-decoding.c
+index fdbb8ea21..c087b46e3 100644
+--- a/grub-core/tests/asn1/tests/object-id-decoding.c
++++ b/grub-core/tests/asn1/tests/object-id-decoding.c
+@@ -85,10 +85,8 @@ test_object_id_decoding (void)
+ sizeof (str));
+ if (ret != tv[i].expected_error)
+ {
+- fprintf (stderr,
+- "%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
+- __LINE__, (unsigned long) i, asn1_strerror (ret),
+- tv[i].expected_error);
++ grub_printf ("%d: asn1_get_object_id_der iter %lu: got '%s' expected %d\n",
++ __LINE__, (unsigned long) i, asn1_strerror (ret), tv[i].expected_error);
+ return 1;
+ }
+
+@@ -97,17 +95,15 @@ test_object_id_decoding (void)
+
+ if (ret_len != tv[i].der_len - 1)
+ {
+- fprintf (stderr,
+- "%d: iter %lu: error in DER, length returned is %d, had %d\n",
+- __LINE__, (unsigned long) i, ret_len, tv[i].der_len - 1);
++ grub_printf ("%d: iter %lu: error in DER, length returned is %d, had %d\n",
++ __LINE__, (unsigned long) i, ret_len, tv[i].der_len - 1);
+ return 1;
+ }
+
+ if (strcmp (tv[i].oid, str) != 0)
+ {
+- fprintf (stderr,
+- "%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
+- __LINE__, (unsigned long) i, str, tv[i].oid);
++ grub_printf ("%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
++ __LINE__, (unsigned long) i, str, tv[i].oid);
+ return 1;
+ }
+
+diff --git a/grub-core/tests/asn1/tests/object-id-encoding.c b/grub-core/tests/asn1/tests/object-id-encoding.c
+index a497015e3..e3da092cc 100644
+--- a/grub-core/tests/asn1/tests/object-id-encoding.c
++++ b/grub-core/tests/asn1/tests/object-id-encoding.c
+@@ -93,33 +93,29 @@ test_object_id_encoding (void)
+ {
+ if (ret == tv[i].expected_error)
+ continue;
+- fprintf (stderr,
+- "%d: iter %lu, encoding of OID failed: %s\n",
+- __LINE__, (unsigned long) i, asn1_strerror (ret));
++ grub_printf ("%d: iter %lu, encoding of OID failed: %s\n",
++ __LINE__, (unsigned long) i, asn1_strerror (ret));
+ return 1;
+ }
+ else if (ret != tv[i].expected_error)
+ {
+- fprintf (stderr,
+- "%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
+- __LINE__, (unsigned long) i, tv[i].oid);
++ grub_printf ("%d: iter %lu, encoding of OID %s succeeded when expecting failure\n",
++ __LINE__, (unsigned long) i, tv[i].oid);
+ return 1;
+ }
+
+ if (der_len != tv[i].der_len || memcmp (der, tv[i].der, der_len) != 0)
+ {
+- fprintf (stderr,
+- "%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
+- __LINE__, (unsigned long) i, tv[i].oid, der_len,
+- tv[i].der_len);
+- fprintf (stderr, "\nGot:\t\t");
++ grub_printf ("%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
++ __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len);
++ grub_printf ("\nGot:\t\t");
+ for (j = 0; j < der_len; j++)
+- fprintf (stderr, "%.2x", der[j]);
++ grub_printf ("%.2x", der[j]);
+
+- fprintf (stderr, "\nExpected:\t");
++ grub_printf ("\nExpected:\t");
+ for (j = 0; j < tv[i].der_len; j++)
+- fprintf (stderr, "%.2x", tv[i].der[j]);
+- fprintf (stderr, "\n");
++ grub_printf ("%.2x", tv[i].der[j]);
++ grub_printf ("\n");
+
+ return 1;
+ }
+diff --git a/grub-core/tests/asn1/tests/octet-string.c b/grub-core/tests/asn1/tests/octet-string.c
+index 8c49c6e0c..d3a35dff8 100644
+--- a/grub-core/tests/asn1/tests/octet-string.c
++++ b/grub-core/tests/asn1/tests/octet-string.c
+@@ -131,9 +131,8 @@ test_octet_string (void)
+ sizeof (str), &str_size);
+ if (ret != tv[i].expected_error)
+ {
+- fprintf (stderr,
+- "%d: asn1_get_octet_der: %s: got %d expected %d\n",
+- __LINE__, tv[i].name, ret, tv[i].expected_error);
++ grub_printf ("%d: asn1_get_octet_der: %s: got %d expected %d\n",
++ __LINE__, tv[i].name, ret, tv[i].expected_error);
+ return 1;
+ }
+ if (tv[i].expected_error)
+@@ -141,27 +140,25 @@ test_octet_string (void)
+
+ if (ret_len != tv[i].der_len - 1)
+ {
+- fprintf (stderr,
+- "%d: error in DER, length returned is %d, had %d\n",
+- __LINE__, ret_len, tv[i].der_len - 1);
++ grub_printf ("%d: error in DER, length returned is %d, had %d\n",
++ __LINE__, ret_len, tv[i].der_len - 1);
+ return 1;
+ }
+
+ if (str_size != tv[i].len
+ || memcmp (tv[i].string, str, tv[i].len) != 0)
+ {
+- fprintf (stderr,
+- "%d: memcmp: %s: got invalid decoding\n",
+- __LINE__, tv[i].name);
++ grub_printf ("%d: memcmp: %s: got invalid decoding\n",
++ __LINE__, tv[i].name);
+
+- fprintf (stderr, "\nGot:\t\t");
++ grub_printf ("\nGot:\t\t");
+ for (j = 0; j < str_size; j++)
+- fprintf (stderr, "%.2x", str[j]);
++ grub_printf ("%.2x", str[j]);
+
+- fprintf (stderr, "\nExpected:\t");
++ grub_printf ("\nExpected:\t");
+ for (j = 0; j < tv[i].len; j++)
+- fprintf (stderr, "%.2x", tv[i].string[j]);
+- fprintf (stderr, "\n");
++ grub_printf ("%.2x", tv[i].string[j]);
++ grub_printf ("\n");
+ return 1;
+ }
+
+@@ -172,8 +169,7 @@ test_octet_string (void)
+ if (der_len != tv[i].der_len - 1
+ || memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
+ {
+- fprintf (stderr,
+- "encoding: %s: got invalid encoding\n", tv[i].name);
++ grub_printf ("encoding: %s: got invalid encoding\n", tv[i].name);
+ return 1;
+ }
+ }
+@@ -185,10 +181,9 @@ test_octet_string (void)
+ (unsigned int *) &der_len);
+ if (ret != tv[i].expected_error)
+ {
+- fprintf (stderr,
+- "%d: asn1_decode_simple_ber: %s: got %s expected %s\n",
+- __LINE__, tv[i].name, asn1_strerror (ret),
+- asn1_strerror (tv[i].expected_error));
++ grub_printf ("%d: asn1_decode_simple_ber: %s: got %s expected %s\n",
++ __LINE__, tv[i].name, asn1_strerror (ret),
++ asn1_strerror (tv[i].expected_error));
+ return 1;
+ }
+ if (tv[i].expected_error)
+@@ -196,25 +191,22 @@ test_octet_string (void)
+
+ if (der_len != tv[i].der_len)
+ {
+- fprintf (stderr,
+- "%d: error: %s: DER, length returned is %d, had %d\n",
+- __LINE__, tv[i].name, der_len, tv[i].der_len);
++ grub_printf ("%d: error: %s: DER, length returned is %d, had %d\n",
++ __LINE__, tv[i].name, der_len, tv[i].der_len);
+ return 1;
+ }
+
+ if (str_size != tv[i].len || memcmp (tv[i].string, tmp, tv[i].len) != 0)
+ {
+- fprintf (stderr,
+- "%d: memcmp: %s: got invalid decoding\n",
+- __LINE__, tv[i].name);
+- fprintf (stderr, "\nGot:\t\t");
++ grub_printf ("%d: memcmp: %s: got invalid decoding\n", __LINE__, tv[i].name);
++ grub_printf ("\nGot:\t\t");
+ for (j = 0; j < str_size; j++)
+- fprintf (stderr, "%.2x", tmp[j]);
++ grub_printf ("%.2x", tmp[j]);
+
+- fprintf (stderr, "\nExpected:\t");
++ grub_printf ("\nExpected:\t");
+ for (j = 0; j < tv[i].len; j++)
+- fprintf (stderr, "%.2x", tv[i].string[j]);
+- fprintf (stderr, "\n");
++ grub_printf ("%.2x", tv[i].string[j]);
++ grub_printf ("\n");
+ return 1;
+ }
+ free (tmp);
+diff --git a/grub-core/tests/asn1/tests/reproducers.c b/grub-core/tests/asn1/tests/reproducers.c
+index d68fc0fbd..278cfed6c 100644
+--- a/grub-core/tests/asn1/tests/reproducers.c
++++ b/grub-core/tests/asn1/tests/reproducers.c
+@@ -58,8 +58,7 @@ test_reproducers (void)
+ result = asn1_array2tree (endless_asn1_tab, &definitions, errorDescription);
+ if (result != ASN1_SUCCESS)
+ {
+- asn1_perror (result);
+- printf ("ErrorDescription = %s\n\n", errorDescription);
++ grub_printf ("Error: %s\nErrorDescription = %s\n\n", asn1_strerror (result), errorDescription);
+ exit (EXIT_FAILURE);
+ }
+
+@@ -69,8 +68,7 @@ test_reproducers (void)
+ result = asn1_array2tree (tab, &definitions, errorDescription);
+ if (result != ASN1_SUCCESS)
+ {
+- asn1_perror (result);
+- printf ("ErrorDescription = %s\n\n", errorDescription);
++ grub_printf ("Error: %s\nErrorDescription = %s\n\n", asn1_strerror (result), errorDescription);
+ exit (EXIT_FAILURE);
+ }
+
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 13/33] asn1_test: return either 0 or 1 to reflect the results
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (11 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 12/33] asn1_test: print the error messages with grub_printf() Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-04 16:34 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 14/33] asn1_test: use the grub-specific functions and types Gary Lin via Grub-devel
` (21 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
Some testcases use exit() to end the test. Since all the asn1 testcases
are invoked as functions, this commit replaces exit() with return to
reflect the test results, so that the main test function can check the
results.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...-either-0-or-1-to-reflect-the-result.patch | 72 +++++++++++++++++++
1 file changed, 72 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0011-asn1_test-return-either-0-or-1-to-reflect-the-result.patch
diff --git a/grub-core/lib/libtasn1-patches/0011-asn1_test-return-either-0-or-1-to-reflect-the-result.patch b/grub-core/lib/libtasn1-patches/0011-asn1_test-return-either-0-or-1-to-reflect-the-result.patch
new file mode 100644
index 000000000..1d6f6a9e6
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0011-asn1_test-return-either-0-or-1-to-reflect-the-result.patch
@@ -0,0 +1,72 @@
+From 39d0c31ea75b8cee4ea5769a7b5c3bb27b21ca83 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Fri, 16 Aug 2024 15:32:39 +0800
+Subject: [PATCH 11/12] asn1_test: return either 0 or 1 to reflect the results
+
+Some testcases use exit() to end the test. Since all the asn1 testcases
+are invoked as functions, this commit replaces exit() with return to
+reflect the test results, so that the main test function can check the
+results.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/tests/asn1/tests/CVE-2018-1000654.c | 6 +++---
+ grub-core/tests/asn1/tests/reproducers.c | 6 +++---
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/grub-core/tests/asn1/tests/CVE-2018-1000654.c b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+index 9eb4d7979..b78667900 100644
+--- a/grub-core/tests/asn1/tests/CVE-2018-1000654.c
++++ b/grub-core/tests/asn1/tests/CVE-2018-1000654.c
+@@ -40,7 +40,7 @@ test_CVE_2018_1000654 (void)
+ {
+ grub_printf ("Error: %s\nErrorDescription = %s\n\n",
+ asn1_strerror (result), errorDescription);
+- exit (1);
++ return 1;
+ }
+
+ asn1_delete_structure (&definitions);
+@@ -52,10 +52,10 @@ test_CVE_2018_1000654 (void)
+ {
+ grub_printf ("Error: %s\nErrorDescription = %s\n\n",
+ asn1_strerror (result), errorDescription);
+- exit (1);
++ return 1;
+ }
+
+ asn1_delete_structure (&definitions);
+
+- exit (0);
++ return 0;
+ }
+diff --git a/grub-core/tests/asn1/tests/reproducers.c b/grub-core/tests/asn1/tests/reproducers.c
+index 278cfed6c..0e3c9fd65 100644
+--- a/grub-core/tests/asn1/tests/reproducers.c
++++ b/grub-core/tests/asn1/tests/reproducers.c
+@@ -59,7 +59,7 @@ test_reproducers (void)
+ if (result != ASN1_SUCCESS)
+ {
+ grub_printf ("Error: %s\nErrorDescription = %s\n\n", asn1_strerror (result), errorDescription);
+- exit (EXIT_FAILURE);
++ return 1;
+ }
+
+ asn1_delete_structure (&definitions);
+@@ -69,10 +69,10 @@ test_reproducers (void)
+ if (result != ASN1_SUCCESS)
+ {
+ grub_printf ("Error: %s\nErrorDescription = %s\n\n", asn1_strerror (result), errorDescription);
+- exit (EXIT_FAILURE);
++ return 1;
+ }
+
+ asn1_delete_structure (&definitions);
+
+- exit (EXIT_SUCCESS);
++ return 0;
+ }
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 14/33] asn1_test: use the grub-specific functions and types
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (12 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 13/33] asn1_test: return either 0 or 1 to reflect the results Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-04 16:36 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 15/33] libtasn1: compile into asn1 module Gary Lin via Grub-devel
` (20 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
This commit converts functions and types to the grub-specific ones:
LONG_MAX -> GRUB_LONG_MAX
INT_MAX -> GRUB_INT_MAX
UINT_MAX -> GRUB_UINT_MAX
size_t -> grub_size_t
memcmp() -> grub_memcmp()
memcpy() -> grub_memcpy()
free() -> grub_free()
strcmp() -> grub_strcmp()
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
---
...he-grub-specific-functions-and-types.patch | 262 ++++++++++++++++++
1 file changed, 262 insertions(+)
create mode 100644 grub-core/lib/libtasn1-patches/0012-asn1_test-use-the-grub-specific-functions-and-types.patch
diff --git a/grub-core/lib/libtasn1-patches/0012-asn1_test-use-the-grub-specific-functions-and-types.patch b/grub-core/lib/libtasn1-patches/0012-asn1_test-use-the-grub-specific-functions-and-types.patch
new file mode 100644
index 000000000..b5cf0fad6
--- /dev/null
+++ b/grub-core/lib/libtasn1-patches/0012-asn1_test-use-the-grub-specific-functions-and-types.patch
@@ -0,0 +1,262 @@
+From 625c23cdb7599ee4fa5e4991864fb69ccb89cae3 Mon Sep 17 00:00:00 2001
+From: Gary Lin <glin@suse.com>
+Date: Fri, 16 Aug 2024 15:46:59 +0800
+Subject: [PATCH 12/12] asn1_test: use the grub-specific functions and types
+
+This commit converts functions and types to the grub-specific ones:
+
+LONG_MAX -> GRUB_LONG_MAX
+INT_MAX -> GRUB_INT_MAX
+UINT_MAX -> GRUB_UINT_MAX
+size_t -> grub_size_t
+memcmp() -> grub_memcmp()
+memcpy() -> grub_memcpy()
+free() -> grub_free()
+strcmp() -> grub_strcmp()
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: Gary Lin <glin@suse.com>
+---
+ grub-core/tests/asn1/tests/Test_overflow.c | 4 ++--
+ grub-core/tests/asn1/tests/Test_simple.c | 22 +++++++++----------
+ grub-core/tests/asn1/tests/Test_strings.c | 8 +++----
+ .../tests/asn1/tests/object-id-decoding.c | 4 ++--
+ .../tests/asn1/tests/object-id-encoding.c | 2 +-
+ grub-core/tests/asn1/tests/octet-string.c | 10 ++++-----
+ 6 files changed, 25 insertions(+), 25 deletions(-)
+
+diff --git a/grub-core/tests/asn1/tests/Test_overflow.c b/grub-core/tests/asn1/tests/Test_overflow.c
+index ffac8507a..65843abf6 100644
+--- a/grub-core/tests/asn1/tests/Test_overflow.c
++++ b/grub-core/tests/asn1/tests/Test_overflow.c
+@@ -43,9 +43,9 @@ test_overflow (void)
+
+ /* Test that values larger than int but smaller than long are
+ rejected. This limitation was introduced with libtasn1 2.12. */
+- if (LONG_MAX > INT_MAX)
++ if (GRUB_LONG_MAX > GRUB_INT_MAX)
+ {
+- unsigned long num = ((long) UINT_MAX) << 2;
++ unsigned long num = ((long) GRUB_UINT_MAX) << 2;
+ unsigned char der[20];
+ int der_len;
+ long l;
+diff --git a/grub-core/tests/asn1/tests/Test_simple.c b/grub-core/tests/asn1/tests/Test_simple.c
+index dc70db191..19613cae8 100644
+--- a/grub-core/tests/asn1/tests/Test_simple.c
++++ b/grub-core/tests/asn1/tests/Test_simple.c
+@@ -81,7 +81,7 @@ test_simple (void)
+ int der_len = sizeof (der);
+ int str_size = sizeof (str);
+ int ret_len, bit_len;
+- size_t i;
++ grub_size_t i;
+
+ {
+ unsigned int etype = 38;
+@@ -127,7 +127,7 @@ test_simple (void)
+ }
+ #endif
+
+- if (der_len != tv[i].derlen || memcmp (der, tv[i].der, der_len) != 0)
++ if (der_len != tv[i].derlen || grub_memcmp (der, tv[i].der, der_len) != 0)
+ {
+ grub_printf ("asn1_bit_der iter %lu\n", (unsigned long) i);
+ return 1;
+@@ -155,12 +155,12 @@ test_simple (void)
+
+ /* 03 04 06 6e 5d c0 DER encoding */
+
+- memcpy (der, "\x04\x06\x6e\x5d\xc0", 5);
++ grub_memcpy (der, "\x04\x06\x6e\x5d\xc0", 5);
+ der_len = 5;
+
+ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
+ if (result != ASN1_SUCCESS || ret_len != 5
+- || bit_len != 18 || memcmp (str, "\x6e\x5d\xc0", 3) != 0)
++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
+ {
+ grub_printf ("asn1_get_bit_der example\n");
+ return 1;
+@@ -168,7 +168,7 @@ test_simple (void)
+
+ der_len = sizeof (der);
+ asn1_bit_der (str, bit_len, der, &der_len);
+- if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+ grub_printf ("asn1_bit_der example roundtrip\n");
+ return 1;
+@@ -176,12 +176,12 @@ test_simple (void)
+
+ /* 03 04 06 6e 5d e0 padded with "100000" */
+
+- memcpy (der, "\x04\x06\x6e\x5d\xe0", 5);
++ grub_memcpy (der, "\x04\x06\x6e\x5d\xe0", 5);
+ der_len = 5;
+
+ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
+ if (result != ASN1_SUCCESS || ret_len != 5
+- || bit_len != 18 || memcmp (str, "\x6e\x5d\xe0", 3) != 0)
++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xe0", 3) != 0)
+ {
+ grub_printf ("asn1_get_bit_der example padded\n");
+ return 1;
+@@ -189,7 +189,7 @@ test_simple (void)
+
+ der_len = sizeof (der);
+ asn1_bit_der (str, bit_len, der, &der_len);
+- if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+ grub_printf ("asn1_bit_der example roundtrip\n");
+ return 1;
+@@ -197,13 +197,13 @@ test_simple (void)
+
+ /* 03 81 04 06 6e 5d c0 long form of length octets */
+
+- memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6);
++ grub_memcpy (der, "\x81\x04\x06\x6e\x5d\xc0", 6);
+ der_len = 6;
+
+ result = asn1_get_bit_der (der, der_len, &ret_len, str, str_size, &bit_len);
+
+ if (result != ASN1_SUCCESS || ret_len != 6
+- || bit_len != 18 || memcmp (str, "\x6e\x5d\xc0", 3) != 0)
++ || bit_len != 18 || grub_memcmp (str, "\x6e\x5d\xc0", 3) != 0)
+ {
+ grub_printf ("asn1_get_bit_der example long form\n");
+ return 1;
+@@ -211,7 +211,7 @@ test_simple (void)
+
+ der_len = sizeof (der);
+ asn1_bit_der (str, bit_len, der, &der_len);
+- if (der_len != 5 || memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
++ if (der_len != 5 || grub_memcmp (der, "\x04\x06\x6e\x5d\xc0", 5) != 0)
+ {
+ grub_printf ("asn1_bit_der example roundtrip\n");
+ return 1;
+diff --git a/grub-core/tests/asn1/tests/Test_strings.c b/grub-core/tests/asn1/tests/Test_strings.c
+index 65c30937f..c7c1afa1b 100644
+--- a/grub-core/tests/asn1/tests/Test_strings.c
++++ b/grub-core/tests/asn1/tests/Test_strings.c
+@@ -94,7 +94,7 @@ test_strings (void)
+ }
+ der_len = tl_len + tv[i].str_len;
+
+- if (der_len != tv[i].der_len || memcmp (tl, tv[i].der, tl_len) != 0)
++ if (der_len != tv[i].der_len || grub_memcmp (tl, tv[i].der, tl_len) != 0)
+ {
+ grub_printf ("DER encoding differs in %u! (size: %u, expected: %u)\n", i, der_len, tv[i].der_len);
+ return 1;
+@@ -110,7 +110,7 @@ test_strings (void)
+ return 1;
+ }
+
+- if (str_len != tv[i].str_len || memcmp (str, tv[i].str, str_len) != 0)
++ if (str_len != tv[i].str_len || grub_memcmp (str, tv[i].str, str_len) != 0)
+ {
+ grub_printf ("DER decoded data differ in %u! (size: %u, expected: %u)\n", i, der_len, tv[i].str_len);
+ return 1;
+@@ -130,12 +130,12 @@ test_strings (void)
+ return 1;
+ }
+
+- if (str_len != ber[i].str_len || memcmp (b, ber[i].str, str_len) != 0)
++ if (str_len != ber[i].str_len || grub_memcmp (b, ber[i].str, str_len) != 0)
+ {
+ grub_printf ("BER decoded data differ in %u! (size: %u, expected: %u)\n", i, str_len, ber[i].str_len);
+ return 1;
+ }
+- free (b);
++ grub_free (b);
+ }
+
+
+diff --git a/grub-core/tests/asn1/tests/object-id-decoding.c b/grub-core/tests/asn1/tests/object-id-decoding.c
+index c087b46e3..91af8cde5 100644
+--- a/grub-core/tests/asn1/tests/object-id-decoding.c
++++ b/grub-core/tests/asn1/tests/object-id-decoding.c
+@@ -74,7 +74,7 @@ test_object_id_decoding (void)
+ {
+ char str[128];
+ int ret, ret_len;
+- size_t i;
++ grub_size_t i;
+
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
+@@ -100,7 +100,7 @@ test_object_id_decoding (void)
+ return 1;
+ }
+
+- if (strcmp (tv[i].oid, str) != 0)
++ if (grub_strcmp (tv[i].oid, str) != 0)
+ {
+ grub_printf ("%d: strcmp iter %lu: got invalid OID: %s, expected: %s\n",
+ __LINE__, (unsigned long) i, str, tv[i].oid);
+diff --git a/grub-core/tests/asn1/tests/object-id-encoding.c b/grub-core/tests/asn1/tests/object-id-encoding.c
+index e3da092cc..f8f98ff17 100644
+--- a/grub-core/tests/asn1/tests/object-id-encoding.c
++++ b/grub-core/tests/asn1/tests/object-id-encoding.c
+@@ -104,7 +104,7 @@ test_object_id_encoding (void)
+ return 1;
+ }
+
+- if (der_len != tv[i].der_len || memcmp (der, tv[i].der, der_len) != 0)
++ if (der_len != tv[i].der_len || grub_memcmp (der, tv[i].der, der_len) != 0)
+ {
+ grub_printf ("%d: iter %lu, re-encoding of OID %s resulted to different string (%d vs %d bytes)\n",
+ __LINE__, (unsigned long) i, tv[i].oid, der_len, tv[i].der_len);
+diff --git a/grub-core/tests/asn1/tests/octet-string.c b/grub-core/tests/asn1/tests/octet-string.c
+index d3a35dff8..dcf0fb808 100644
+--- a/grub-core/tests/asn1/tests/octet-string.c
++++ b/grub-core/tests/asn1/tests/octet-string.c
+@@ -116,7 +116,7 @@ test_octet_string (void)
+ int str_size = sizeof (str);
+ unsigned char *tmp = NULL;
+ int ret, ret_len, j;
+- size_t i;
++ grub_size_t i;
+
+ for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+ {
+@@ -146,7 +146,7 @@ test_octet_string (void)
+ }
+
+ if (str_size != tv[i].len
+- || memcmp (tv[i].string, str, tv[i].len) != 0)
++ || grub_memcmp (tv[i].string, str, tv[i].len) != 0)
+ {
+ grub_printf ("%d: memcmp: %s: got invalid decoding\n",
+ __LINE__, tv[i].name);
+@@ -167,7 +167,7 @@ test_octet_string (void)
+ asn1_octet_der (str, str_size, der, &der_len);
+
+ if (der_len != tv[i].der_len - 1
+- || memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
++ || grub_memcmp (tv[i].der_str + 1, der, tv[i].der_len - 1) != 0)
+ {
+ grub_printf ("encoding: %s: got invalid encoding\n", tv[i].name);
+ return 1;
+@@ -196,7 +196,7 @@ test_octet_string (void)
+ return 1;
+ }
+
+- if (str_size != tv[i].len || memcmp (tv[i].string, tmp, tv[i].len) != 0)
++ if (str_size != tv[i].len || grub_memcmp (tv[i].string, tmp, tv[i].len) != 0)
+ {
+ grub_printf ("%d: memcmp: %s: got invalid decoding\n", __LINE__, tv[i].name);
+ grub_printf ("\nGot:\t\t");
+@@ -209,7 +209,7 @@ test_octet_string (void)
+ grub_printf ("\n");
+ return 1;
+ }
+- free (tmp);
++ grub_free (tmp);
+ tmp = NULL;
+
+ }
+--
+2.35.3
+
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 15/33] libtasn1: compile into asn1 module
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (13 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 14/33] asn1_test: use the grub-specific functions and types Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 16/33] asn1_test: test module for libtasn1 Gary Lin via Grub-devel
` (19 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Daniel Axtens <dja@axtens.net>
Create a wrapper file that specifies the module license.
Set up the makefile so it is built.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
autogen.sh | 19 +++++++++++++++++++
grub-core/Makefile.core.def | 15 +++++++++++++++
grub-core/lib/libtasn1_wrap/wrap.c | 27 +++++++++++++++++++++++++++
3 files changed, 61 insertions(+)
create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
diff --git a/autogen.sh b/autogen.sh
index 195daa541..d08dc9a31 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -51,6 +51,25 @@ 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
+echo "Importing libtasn1..."
+if [ -d grub-core/lib/libtasn1-grub ]; then
+ rm -rf grub-core/lib/libtasn1-grub
+fi
+
+mkdir -p grub-core/lib/libtasn1-grub/lib
+cp grub-core/lib/libtasn1/lib/*.[ch] grub-core/lib/libtasn1-grub/lib
+cp grub-core/lib/libtasn1/libtasn1.h grub-core/lib/libtasn1-grub/
+
+for patch in \
+ 0001-libtasn1-disable-code-not-needed-in-grub.patch \
+ 0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch \
+ 0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch \
+ 0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch \
+ 0005-libtasn1-Use-grub_divmod64-for-division.patch \
+ 0006-libtasn1-fix-the-potential-buffer-overrun.patch ; do
+ patch -p1 -i grub-core/lib/libtasn1-patches/$patch
+done
+
echo "Generating Automake input..."
# Automake doesn't like including files from a path outside the project.
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 063ef5dd7..cb4c5800e 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2606,3 +2606,18 @@ module = {
enable = efi;
depends = part_gpt;
};
+
+module = {
+ name = asn1;
+ common = lib/libtasn1-grub/lib/decoding.c;
+ common = lib/libtasn1-grub/lib/coding.c;
+ common = lib/libtasn1-grub/lib/element.c;
+ common = lib/libtasn1-grub/lib/structure.c;
+ common = lib/libtasn1-grub/lib/parser_aux.c;
+ common = lib/libtasn1-grub/lib/gstr.c;
+ common = lib/libtasn1-grub/lib/errors.c;
+ common = lib/libtasn1_wrap/wrap.c;
+ cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
+ /* -Wno-type-limits comes from configure.ac of libtasn1 */
+ cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1-grub -I$(srcdir)/lib/libtasn1-grub/lib -Wno-type-limits';
+};
diff --git a/grub-core/lib/libtasn1_wrap/wrap.c b/grub-core/lib/libtasn1_wrap/wrap.c
new file mode 100644
index 000000000..fcada55a8
--- /dev/null
+++ b/grub-core/lib/libtasn1_wrap/wrap.c
@@ -0,0 +1,27 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2020 IBM Corporation
+ * Copyright (C) 2024 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>
+
+/*
+ * libtasn1 is provided under LGPL2.1+, which is compatible
+ * with GPL3+. As GRUB as a whole is under GPL3+, this module
+ * is therefore under GPL3+ also.
+ */
+GRUB_MOD_LICENSE ("GPLv3+");
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 16/33] asn1_test: test module for libtasn1
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (14 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 15/33] libtasn1: compile into asn1 module Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 17/33] libtasn1: Add the documentation Gary Lin via Grub-devel
` (18 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Daniel Axtens <dja@axtens.net>
Import tests from libtasn1 that use functionality we import.
This test module is integrated into functional_test so that the
user can run the test in grub shell.
This doesn't test the full decoder but that will be exercised in
test suites for coming patch sets.
Add testcase target in accordance with
5e10be48e5 tests: Add check-native and check-nonnative make targets
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
Makefile.util.def | 6 ++++
autogen.sh | 15 +++++++-
grub-core/Makefile.core.def | 15 ++++++++
grub-core/tests/asn1/asn1_test.c | 50 +++++++++++++++++++++++++++
grub-core/tests/asn1/asn1_test.h | 45 ++++++++++++++++++++++++
grub-core/tests/lib/functional_test.c | 1 +
tests/asn1_test.in | 11 ++++++
7 files changed, 142 insertions(+), 1 deletion(-)
create mode 100644 grub-core/tests/asn1/asn1_test.c
create mode 100644 grub-core/tests/asn1/asn1_test.h
create mode 100644 tests/asn1_test.in
diff --git a/Makefile.util.def b/Makefile.util.def
index 0f74a1680..fe70cf9bd 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -1257,6 +1257,12 @@ script = {
common = tests/luks2_test.in;
};
+script = {
+ testcase = native;
+ name = asn1_test;
+ common = tests/asn1_test.in;
+};
+
program = {
testcase = native;
name = example_unit_test;
diff --git a/autogen.sh b/autogen.sh
index d08dc9a31..494c66293 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -60,13 +60,26 @@ mkdir -p grub-core/lib/libtasn1-grub/lib
cp grub-core/lib/libtasn1/lib/*.[ch] grub-core/lib/libtasn1-grub/lib
cp grub-core/lib/libtasn1/libtasn1.h grub-core/lib/libtasn1-grub/
+if [ -d grub-core/tests/asn1/tests ]; then
+ rm -rf grub-core/tests/asn1/tests
+fi
+
+mkdir grub-core/tests/asn1/tests
+cp grub-core/lib/libtasn1/tests/*.[ch] grub-core/tests/asn1/tests
+
for patch in \
0001-libtasn1-disable-code-not-needed-in-grub.patch \
0002-libtasn1-replace-strcat-with-strcpy-in-_asn1_str_cat.patch \
0003-libtasn1-replace-strcat-with-_asn1_str_cat.patch \
0004-libtasn1-adjust-the-header-paths-in-libtasn1.h.patch \
0005-libtasn1-Use-grub_divmod64-for-division.patch \
- 0006-libtasn1-fix-the-potential-buffer-overrun.patch ; do
+ 0006-libtasn1-fix-the-potential-buffer-overrun.patch \
+ 0007-asn1_test-include-asn1_test.h-only.patch \
+ 0008-asn1_test-rename-the-main-functions-to-the-test-name.patch \
+ 0009-asn1_test-remove-verbose-and-the-unnecessary-printf.patch \
+ 0010-asn1_test-print-the-error-messages-with-grub_printf.patch \
+ 0011-asn1_test-return-either-0-or-1-to-reflect-the-result.patch \
+ 0012-asn1_test-use-the-grub-specific-functions-and-types.patch ; do
patch -p1 -i grub-core/lib/libtasn1-patches/$patch
done
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index cb4c5800e..a38955e18 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2621,3 +2621,18 @@ module = {
/* -Wno-type-limits comes from configure.ac of libtasn1 */
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/libtasn1-grub -I$(srcdir)/lib/libtasn1-grub/lib -Wno-type-limits';
};
+
+module = {
+ name = asn1_test;
+ common = tests/asn1/tests/CVE-2018-1000654.c;
+ common = tests/asn1/tests/object-id-decoding.c;
+ common = tests/asn1/tests/object-id-encoding.c;
+ common = tests/asn1/tests/octet-string.c;
+ common = tests/asn1/tests/reproducers.c;
+ common = tests/asn1/tests/Test_overflow.c;
+ common = tests/asn1/tests/Test_simple.c;
+ common = tests/asn1/tests/Test_strings.c;
+ common = tests/asn1/asn1_test.c;
+ cflags = '-Wno-uninitialized';
+ cppflags = '-I$(srcdir)/lib/libtasn1-grub -I$(srcdir)/tests/asn1/';
+};
diff --git a/grub-core/tests/asn1/asn1_test.c b/grub-core/tests/asn1/asn1_test.c
new file mode 100644
index 000000000..69606b004
--- /dev/null
+++ b/grub-core/tests/asn1/asn1_test.c
@@ -0,0 +1,50 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2020 IBM Corporation
+ * Copyright (C) 2024 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/test.h>
+#include <grub/dl.h>
+#include "asn1_test.h"
+
+/*
+ * libtasn1 tests - from which this is derived - are provided under GPL3+.
+ */
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static void
+asn1_test (void)
+{
+ grub_test_assert (test_CVE_2018_1000654 () == 0, "CVE-2018-1000654 test failed");
+
+ grub_test_assert (test_object_id_encoding () == 0, "ASN.1 object ID encoding test failed");
+
+ grub_test_assert (test_object_id_decoding () == 0, "ASN.1 object ID decoding test failed");
+
+ grub_test_assert (test_octet_string () == 0, "ASN.1 octet string test failed");
+
+ grub_test_assert (test_overflow () == 0, "ASN.1 overflow test failed");
+
+ grub_test_assert (test_reproducers () == 0, "ASN.1 reproducers test failed");
+
+ grub_test_assert (test_simple () == 0, "ASN.1 simple test failed");
+
+ grub_test_assert (test_strings () == 0, "ASN.1 strings test fail" );
+}
+
+/* Register asn1_test method as a functional test. */
+GRUB_FUNCTIONAL_TEST (asn1_test, asn1_test);
diff --git a/grub-core/tests/asn1/asn1_test.h b/grub-core/tests/asn1/asn1_test.h
new file mode 100644
index 000000000..8e83d70f5
--- /dev/null
+++ b/grub-core/tests/asn1/asn1_test.h
@@ -0,0 +1,45 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2020 IBM Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef LIBTASN1_WRAP_TESTS_H
+#define LIBTASN1_WRAP_TESTS_H
+
+#include <libtasn1.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+
+extern int test_CVE_2018_1000654 (void);
+
+extern int test_object_id_encoding (void);
+
+extern int test_object_id_decoding (void);
+
+extern int test_octet_string (void);
+
+extern int test_overflow (void);
+
+extern int test_reproducers (void);
+
+extern int test_simple (void);
+
+extern int test_strings (void);
+
+#endif
diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
index 96781fb39..38e981f2c 100644
--- a/grub-core/tests/lib/functional_test.c
+++ b/grub-core/tests/lib/functional_test.c
@@ -79,6 +79,7 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)),
grub_dl_load ("cmp_test");
grub_dl_load ("mul_test");
grub_dl_load ("shift_test");
+ grub_dl_load ("asn1_test");
FOR_LIST_ELEMENTS (test, grub_test_list)
ok = !grub_test_run (test) && ok;
diff --git a/tests/asn1_test.in b/tests/asn1_test.in
new file mode 100644
index 000000000..8f18ee6bb
--- /dev/null
+++ b/tests/asn1_test.in
@@ -0,0 +1,11 @@
+#! @BUILD_SHEBANG@
+set -e
+
+. "@builddir@/grub-core/modinfo.sh"
+
+out=`echo functional_test asn1_test | @builddir@/grub-shell`
+
+if [ "$(echo "$out" | tail -n 1)" != "ALL TESTS PASSED" ]; then
+ echo "ASN.1 test failure: $out"
+ exit 1
+fi
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 17/33] libtasn1: Add the documentation
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (15 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 16/33] asn1_test: test module for libtasn1 Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 18/33] key_protector: Add key protectors framework Gary Lin via Grub-devel
` (17 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
Document libtasn1 in docs/grub-dev.texi and add the upgrade steps.
Also add the patches to make libtasn1 compatible with grub code.
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub-dev.texi | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 1276c5930..0e136790b 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -506,6 +506,7 @@ to update it.
* Gnulib::
* jsmn::
* minilzo::
+* libtasn1::
@end menu
@node Gnulib
@@ -596,6 +597,40 @@ cp minilzo-2.10/*.[hc] grub-core/lib/minilzo
rm -r minilzo-2.10*
@end example
+@node libtasn1
+@section libtasn1
+
+libtasn1 is a library providing Abstract Syntax Notation One (ASN.1, as
+specified by the X.680 ITU-T recommendation) parsing and structures management,
+and Distinguished Encoding Rules (DER, as per X.690) encoding and decoding
+functions.
+
+To upgrade to a new version of the libtasn1 library, download the release
+tarball and copy the files into the target directory:
+
+@example
+curl -L -O https://ftp.gnu.org/gnu/libtasn1/libtasn1-4.19.0.tar.gz
+tar xf libtasn1-4.19.0.tar.gz
+rm -rf grub-core/lib/libtasn1/
+mkdir -p grub-core/lib/libtasn1/lib/
+mkdir -p grub-core/lib/libtasn1/tests/
+cp libtasn1-4.19.0/@lbracechar{}README.md,COPYING@rbracechar{} grub-core/lib/libtasn1/
+cp libtasn1-4.19.0/lib/@lbracechar{}coding.c,decoding.c,element.c,element.h,errors.c,gstr.c,gstr.h,int.h,parser_aux.c,parser_aux.h,structure.c,structure.h@rbracechar{} grub-core/lib/libtasn1/lib/
+cp libtasn1-4.19.0/lib/includes/libtasn1.h grub-core/lib/libtasn1/
+cp libtasn1-4.19.0/tests/@lbracechar{}CVE-2018-1000654-1_asn1_tab.h,CVE-2018-1000654-2_asn1_tab.h,CVE-2018-1000654.c,object-id-decoding.c,object-id-encoding.c,octet-string.c,reproducers.c,Test_overflow.c,Test_simple.c,Test_strings.c@rbracechar{} grub-core/lib/libtasn1/tests
+rm -rf libtasn1-4.19.0*
+@end example
+
+After upgrading the library, it may be necessary to apply the patches in
+@file{grub-core/lib/libtasn1-patches/} to adjust the code to be compatible with
+GRUB. These patches were needed to use the current version of libtasn1. The
+existing patches may not apply cleanly, apply at all, or even be needed for a
+newer version of the library, and other patches may be needed due to changes in
+the newer version. If existing patches need to be refreshed to apply cleanly,
+please include updated patches as part of the a patch set sent to the list.
+If new patches are needed or existing patches are not needed, also please send
+additions or removals as part of any patch set upgrading libtasn1.
+
@node Debugging
@chapter Debugging
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 18/33] key_protector: Add key protectors framework
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (16 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 17/33] libtasn1: Add the documentation Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 19/33] tss2: Add TPM2 buffer handling functions Gary Lin via Grub-devel
` (16 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Hernan Gatta <hegatta@linux.microsoft.com>
A key protector encapsulates functionality to retrieve an unlocking key
for a fully-encrypted disk from a specific source. A key protector
module registers itself with the key protectors framework when it is
loaded and unregisters when unloaded. Additionally, a key protector may
accept parameters that describe how it should operate.
The key protectors framework, besides offering registration and
unregistration functions, also offers a one-stop routine for finding and
invoking a key protector by name. If a key protector with the specified
name exists and if an unlocking key is successfully retrieved by it, the
function returns to the caller the retrieved key and its length.
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.am | 1 +
grub-core/Makefile.core.def | 5 +++
grub-core/disk/key_protector.c | 73 ++++++++++++++++++++++++++++++++++
include/grub/key_protector.h | 47 ++++++++++++++++++++++
4 files changed, 126 insertions(+)
create mode 100644 grub-core/disk/key_protector.c
create mode 100644 include/grub/key_protector.h
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 1eda467e0..e50db8106 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -90,6 +90,7 @@ endif
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/key_protector.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index a38955e18..37f131ae2 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1282,6 +1282,11 @@ module = {
common = disk/raid6_recover.c;
};
+module = {
+ name = key_protector;
+ common = disk/key_protector.c;
+};
+
module = {
name = scsi;
common = disk/scsi.c;
diff --git a/grub-core/disk/key_protector.c b/grub-core/disk/key_protector.c
new file mode 100644
index 000000000..0d146c1c0
--- /dev/null
+++ b/grub-core/disk/key_protector.c
@@ -0,0 +1,73 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/list.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/key_protector.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct grub_key_protector *grub_key_protectors = NULL;
+
+grub_err_t
+grub_key_protector_register (struct grub_key_protector *protector)
+{
+ if (protector == NULL || protector->name == NULL || protector->name[0] == '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector for registration");
+
+ if (grub_key_protectors != NULL &&
+ grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), protector->name) != NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Key protector '%s' already registered", protector->name);
+
+ grub_list_push (GRUB_AS_LIST_P (&grub_key_protectors), GRUB_AS_LIST (protector));
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_key_protector_unregister (struct grub_key_protector *protector)
+{
+ if (protector == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector for unregistration");
+
+ grub_list_remove (GRUB_AS_LIST (protector));
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_key_protector_recover_key (const char *protector, grub_uint8_t **key,
+ grub_size_t *key_size)
+{
+ struct grub_key_protector *kp = NULL;
+
+ if (grub_key_protectors == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "No key protector registered");
+
+ if (protector == NULL || protector[0] == '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector");
+
+ kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), protector);
+ if (kp == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Key protector '%s' not found", protector);
+
+ return kp->recover_key (key, key_size);
+}
diff --git a/include/grub/key_protector.h b/include/grub/key_protector.h
new file mode 100644
index 000000000..00b15c13d
--- /dev/null
+++ b/include/grub/key_protector.h
@@ -0,0 +1,47 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_PROTECTOR_HEADER
+#define GRUB_PROTECTOR_HEADER 1
+
+#include <grub/err.h>
+#include <grub/types.h>
+
+struct grub_key_protector
+{
+ struct grub_key_protector *next;
+ struct grub_key_protector **prev;
+
+ const char *name;
+
+ grub_err_t (*recover_key) (grub_uint8_t **key, grub_size_t *key_size);
+};
+
+grub_err_t
+grub_key_protector_register (struct grub_key_protector *protector);
+
+grub_err_t
+grub_key_protector_unregister (struct grub_key_protector *protector);
+
+grub_err_t
+grub_key_protector_recover_key (const char *protector,
+ grub_uint8_t **key,
+ grub_size_t *key_size);
+
+#endif /* ! GRUB_PROTECTOR_HEADER */
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 19/33] tss2: Add TPM2 buffer handling functions
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (17 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 18/33] key_protector: Add key protectors framework Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 20/33] tss2: Add TPM2 types and Marshal/Unmarshal functions Gary Lin via Grub-devel
` (15 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
As the prepartion to support TPM2 Software Stack (TSS2), this commit
implements the TPM2 buffer handling functions to pack data for the TPM2
commands and unpack the data from the response.
Cc: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/tss2/buffer.c | 147 +++++++++++++++++++++++++++++++
grub-core/lib/tss2/tss2_buffer.h | 64 ++++++++++++++
2 files changed, 211 insertions(+)
create mode 100644 grub-core/lib/tss2/buffer.c
create mode 100644 grub-core/lib/tss2/tss2_buffer.h
diff --git a/grub-core/lib/tss2/buffer.c b/grub-core/lib/tss2/buffer.c
new file mode 100644
index 000000000..16d59a8f5
--- /dev/null
+++ b/grub-core/lib/tss2/buffer.c
@@ -0,0 +1,147 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/misc.h>
+
+#include <tss2_buffer.h>
+
+void grub_tpm2_buffer_init (grub_tpm2_buffer_t buffer)
+{
+ grub_memset (buffer->data, 0, sizeof (buffer->data));
+ buffer->size = 0;
+ buffer->offset = 0;
+ buffer->cap = sizeof (buffer->data);
+ buffer->error = 0;
+}
+
+void
+grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void *data, grub_size_t size)
+{
+ grub_uint32_t r = buffer->cap - buffer->size;
+
+ if (buffer->error)
+ return;
+
+ if (size > r)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ grub_memcpy (&buffer->data[buffer->size], (void *) data, size);
+ buffer->size += size;
+}
+
+void
+grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value)
+{
+ grub_tpm2_buffer_pack (buffer, (const void *) &value, sizeof (value));
+}
+
+void
+grub_tpm2_buffer_pack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t value)
+{
+ grub_uint16_t tmp = grub_cpu_to_be16 (value);
+
+ grub_tpm2_buffer_pack (buffer, (const void *) &tmp, sizeof (tmp));
+}
+
+void
+grub_tpm2_buffer_pack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t value)
+{
+ grub_uint32_t tmp = grub_cpu_to_be32 (value);
+
+ grub_tpm2_buffer_pack (buffer, (const void *) &tmp, sizeof (tmp));
+}
+
+void
+grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void *data, grub_size_t size)
+{
+ grub_uint32_t r = buffer->size - buffer->offset;
+
+ if (buffer->error)
+ return;
+
+ if (size > r)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ grub_memcpy (data, &buffer->data[buffer->offset], size);
+ buffer->offset += size;
+}
+
+void
+grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t *value)
+{
+ grub_uint32_t r = buffer->size - buffer->offset;
+
+ if (buffer->error)
+ return;
+
+ if (sizeof (*value) > r)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ grub_memcpy (value, &buffer->data[buffer->offset], sizeof (*value));
+ buffer->offset += sizeof (*value);
+}
+
+void
+grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t *value)
+{
+ grub_uint16_t tmp;
+ grub_uint32_t r = buffer->size - buffer->offset;
+
+ if (buffer->error)
+ return;
+
+ if (sizeof (tmp) > r)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ grub_memcpy (&tmp, &buffer->data[buffer->offset], sizeof (tmp));
+ buffer->offset += sizeof (tmp);
+ *value = grub_be_to_cpu16 (tmp);
+}
+
+void
+grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t *value)
+{
+ grub_uint32_t tmp;
+ grub_uint32_t r = buffer->size - buffer->offset;
+
+ if (buffer->error)
+ return;
+
+ if (sizeof (tmp) > r)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ grub_memcpy (&tmp, &buffer->data[buffer->offset], sizeof (tmp));
+ buffer->offset += sizeof (tmp);
+ *value = grub_be_to_cpu32 (tmp);
+}
diff --git a/grub-core/lib/tss2/tss2_buffer.h b/grub-core/lib/tss2/tss2_buffer.h
new file mode 100644
index 000000000..fb9db1aed
--- /dev/null
+++ b/grub-core/lib/tss2/tss2_buffer.h
@@ -0,0 +1,64 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_BUFFER_HEADER
+#define GRUB_TPM2_BUFFER_HEADER 1
+
+#include <grub/types.h>
+
+#define GRUB_TPM2_BUFFER_CAPACITY 4096
+
+struct grub_tpm2_buffer
+{
+ grub_uint8_t data[GRUB_TPM2_BUFFER_CAPACITY];
+ grub_size_t size;
+ grub_size_t offset;
+ grub_size_t cap;
+ bool error;
+};
+typedef struct grub_tpm2_buffer *grub_tpm2_buffer_t;
+
+extern void
+grub_tpm2_buffer_init (grub_tpm2_buffer_t buffer);
+
+extern void
+grub_tpm2_buffer_pack (grub_tpm2_buffer_t buffer, const void *data, grub_size_t size);
+
+extern void
+grub_tpm2_buffer_pack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t value);
+
+extern void
+grub_tpm2_buffer_pack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t value);
+
+extern void
+grub_tpm2_buffer_pack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t value);
+
+extern void
+grub_tpm2_buffer_unpack (grub_tpm2_buffer_t buffer, void *data, grub_size_t size);
+
+extern void
+grub_tpm2_buffer_unpack_u8 (grub_tpm2_buffer_t buffer, grub_uint8_t *value);
+
+extern void
+grub_tpm2_buffer_unpack_u16 (grub_tpm2_buffer_t buffer, grub_uint16_t *value);
+
+extern void
+grub_tpm2_buffer_unpack_u32 (grub_tpm2_buffer_t buffer, grub_uint32_t *value);
+
+#endif /* ! GRUB_TPM2_BUFFER_HEADER */
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 20/33] tss2: Add TPM2 types and Marshal/Unmarshal functions
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (18 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 19/33] tss2: Add TPM2 buffer handling functions Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support Gary Lin via Grub-devel
` (14 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
This commit adds the necessary TPM2 types and structs as the preparation
for the TPM2 Software Stack (TSS2) support. The Marshal/Unmarshal
functions are also added to handle the data structure to be submitted to
TPM2 commands and to be received from the response.
Cc: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/tss2/tss2_mu.c | 1174 +++++++++++++++++++++++++++++
grub-core/lib/tss2/tss2_mu.h | 397 ++++++++++
grub-core/lib/tss2/tss2_structs.h | 773 +++++++++++++++++++
grub-core/lib/tss2/tss2_types.h | 404 ++++++++++
4 files changed, 2748 insertions(+)
create mode 100644 grub-core/lib/tss2/tss2_mu.c
create mode 100644 grub-core/lib/tss2/tss2_mu.h
create mode 100644 grub-core/lib/tss2/tss2_structs.h
create mode 100644 grub-core/lib/tss2/tss2_types.h
diff --git a/grub-core/lib/tss2/tss2_mu.c b/grub-core/lib/tss2/tss2_mu.c
new file mode 100644
index 000000000..86134cc0a
--- /dev/null
+++ b/grub-core/lib/tss2/tss2_mu.c
@@ -0,0 +1,1174 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/misc.h>
+
+#include <tss2_mu.h>
+
+void
+grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_AUTH_COMMAND_t *authCommand)
+{
+ grub_uint32_t start;
+ grub_uint32_t tmp;
+
+ grub_tpm2_buffer_pack_u32 (buffer, 0);
+ start = buffer->size;
+
+ grub_tpm2_buffer_pack_u32 (buffer, authCommand->sessionHandle);
+
+ grub_tpm2_buffer_pack_u16 (buffer, authCommand->nonce.size);
+ grub_tpm2_buffer_pack (buffer, authCommand->nonce.buffer, authCommand->nonce.size);
+
+ grub_tpm2_buffer_pack_u8 (buffer, *((const grub_uint8_t *) &authCommand->sessionAttributes));
+
+ grub_tpm2_buffer_pack_u16 (buffer, authCommand->hmac.size);
+ grub_tpm2_buffer_pack (buffer, authCommand->hmac.buffer, authCommand->hmac.size);
+
+ tmp = grub_cpu_to_be32 (buffer->size - start);
+ grub_memcpy (&buffer->data[start - sizeof (grub_uint32_t)], &tmp, sizeof (tmp));
+}
+
+void
+grub_Tss2_MU_TPM2B_Marshal (grub_tpm2_buffer_t buffer,
+ const grub_uint16_t size,
+ const grub_uint8_t *b)
+{
+ grub_uint16_t i;
+
+ grub_tpm2_buffer_pack_u16 (buffer, size);
+
+ for (i = 0; i < size; i++)
+ grub_tpm2_buffer_pack_u8 (buffer, b[i]);
+}
+
+void
+grub_Tss2_MU_TPMU_SYM_KEY_BITS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_SYM_OBJECT_t algorithm,
+ const TPMU_SYM_KEY_BITS_t *p)
+{
+ switch (algorithm)
+ {
+ case TPM_ALG_AES:
+ case TPM_ALG_SM4:
+ case TPM_ALG_CAMELLIA:
+ case TPM_ALG_XOR:
+ grub_tpm2_buffer_pack_u16 (buffer, *((const grub_uint16_t *) p));
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMU_SYM_MODE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_SYM_OBJECT_t algorithm,
+ const TPMU_SYM_MODE_t *p)
+{
+ switch (algorithm)
+ {
+ case TPM_ALG_AES:
+ case TPM_ALG_SM4:
+ case TPM_ALG_CAMELLIA:
+ grub_tpm2_buffer_pack_u16 (buffer, *((const grub_uint16_t *) p));
+ break;
+ case TPM_ALG_XOR:
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_SYM_DEF_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SYM_DEF_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->algorithm);
+ grub_Tss2_MU_TPMU_SYM_KEY_BITS_Marshal (buffer, p->algorithm, &p->keyBits);
+ grub_Tss2_MU_TPMU_SYM_MODE_Marshal (buffer, p->algorithm, &p->mode);
+}
+
+void
+grub_Tss2_MU_TPMS_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_PCR_SELECTION_t *pcrSelection)
+{
+ grub_uint32_t i;
+
+ grub_tpm2_buffer_pack_u16 (buffer, pcrSelection->hash);
+ grub_tpm2_buffer_pack_u8 (buffer, pcrSelection->sizeOfSelect);
+
+ for (i = 0; i < pcrSelection->sizeOfSelect; i++)
+ grub_tpm2_buffer_pack_u8 (buffer, pcrSelection->pcrSelect[i]);
+}
+
+void
+grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer,
+ const TPML_PCR_SELECTION_t *pcrSelection)
+{
+ grub_uint32_t i;
+
+ grub_tpm2_buffer_pack_u32 (buffer, pcrSelection->count);
+
+ for (i = 0; i < pcrSelection->count; i++)
+ grub_Tss2_MU_TPMS_PCR_SELECTION_Marshal (buffer, &pcrSelection->pcrSelections[i]);
+}
+
+void
+grub_Tss2_MU_TPMA_OBJECT_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMA_OBJECT_t *p)
+{
+ grub_tpm2_buffer_pack_u32 (buffer, *((const grub_uint32_t *) p));
+}
+
+void
+grub_Tss2_MU_TPMS_SCHEME_XOR_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SCHEME_XOR_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->hashAlg);
+ grub_tpm2_buffer_pack_u16 (buffer, p->kdf);
+}
+
+void
+grub_Tss2_MU_TPMS_SCHEME_HMAC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SCHEME_HMAC_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->hashAlg);
+}
+
+void
+grub_Tss2_MU_TPMU_SCHEME_KEYEDHASH_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_KEYEDHASH_SCHEME_t scheme,
+ const TPMU_SCHEME_KEYEDHASH_t *p)
+{
+ switch (scheme)
+ {
+ case TPM_ALG_HMAC:
+ grub_Tss2_MU_TPMS_SCHEME_HMAC_Marshal (buffer, &p->hmac);
+ break;
+ case TPM_ALG_XOR:
+ grub_Tss2_MU_TPMS_SCHEME_XOR_Marshal (buffer, &p->exclusiveOr);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_KEYEDHASH_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_KEYEDHASH_SCHEME_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->scheme);
+ grub_Tss2_MU_TPMU_SCHEME_KEYEDHASH_Marshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMS_KEYEDHASH_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_KEYEDHASH_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_KEYEDHASH_SCHEME_Marshal (buffer, &p->scheme);
+}
+
+void
+grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SYM_DEF_OBJECT_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->algorithm);
+ grub_Tss2_MU_TPMU_SYM_KEY_BITS_Marshal (buffer, p->algorithm, &p->keyBits);
+ grub_Tss2_MU_TPMU_SYM_MODE_Marshal (buffer, p->algorithm, &p->mode);
+}
+
+void
+grub_Tss2_MU_TPMU_ASYM_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_RSA_DECRYPT_t scheme,
+ const TPMU_ASYM_SCHEME_t *p __attribute__ ((unused)))
+{
+ switch (scheme)
+ {
+ case TPM_ALG_NULL:
+ break;
+ default:
+ /* Unsupported */
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_RSA_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_RSA_SCHEME_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->scheme);
+ grub_Tss2_MU_TPMU_ASYM_SCHEME_Marshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMS_RSA_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_RSA_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->symmetric);
+ grub_Tss2_MU_TPMT_RSA_SCHEME_Marshal (buffer, &p->scheme);
+ grub_tpm2_buffer_pack_u16 (buffer, p->keyBits);
+ grub_tpm2_buffer_pack_u32 (buffer, p->exponent);
+}
+
+void
+grub_Tss2_MU_TPMS_SYMCIPHER_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SYMCIPHER_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->sym);
+}
+
+void
+grub_Tss2_MU_TPMT_ECC_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_ECC_SCHEME_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->scheme);
+ grub_Tss2_MU_TPMU_ASYM_SCHEME_Marshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMU_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_KDF_t scheme,
+ const TPMU_KDF_SCHEME_t *p)
+{
+ switch (scheme)
+ {
+ case TPM_ALG_MGF1:
+ grub_tpm2_buffer_pack_u16 (buffer, p->mgf1.hashAlg);
+ break;
+ case TPM_ALG_KDF1_SP800_56A:
+ grub_tpm2_buffer_pack_u16 (buffer, p->kdf1_sp800_56a.hashAlg);
+ break;
+ case TPM_ALG_KDF2:
+ grub_tpm2_buffer_pack_u16 (buffer, p->kdf2.hashAlg);
+ break;
+ case TPM_ALG_KDF1_SP800_108:
+ grub_tpm2_buffer_pack_u16 (buffer, p->kdf1_sp800_108.hashAlg);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_KDF_SCHEME_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->scheme);
+ grub_Tss2_MU_TPMU_KDF_SCHEME_Marshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMS_ECC_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_ECC_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Marshal (buffer, &p->symmetric);
+ grub_Tss2_MU_TPMT_ECC_SCHEME_Marshal (buffer, &p->scheme);
+ grub_tpm2_buffer_pack_u16 (buffer, p->curveID);
+ grub_Tss2_MU_TPMT_KDF_SCHEME_Marshal (buffer, &p->kdf);
+}
+
+void
+grub_Tss2_MU_TPMU_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const grub_uint32_t type,
+ const TPMU_PUBLIC_PARMS_t *p)
+{
+ switch (type)
+ {
+ case TPM_ALG_KEYEDHASH:
+ grub_Tss2_MU_TPMS_KEYEDHASH_PARMS_Marshal (buffer, &p->keyedHashDetail);
+ break;
+ case TPM_ALG_SYMCIPHER:
+ grub_Tss2_MU_TPMS_SYMCIPHER_PARMS_Marshal (buffer, &p->symDetail);
+ break;
+ case TPM_ALG_RSA:
+ grub_Tss2_MU_TPMS_RSA_PARMS_Marshal (buffer, &p->rsaDetail);
+ break;
+ case TPM_ALG_ECC:
+ grub_Tss2_MU_TPMS_ECC_PARMS_Marshal (buffer, &p->eccDetail);
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMS_ECC_POINT_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_ECC_POINT_t *p)
+{
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->x.size, p->x.buffer);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->y.size, p->y.buffer);
+}
+
+void
+grub_Tss2_MU_TPMU_PUBLIC_ID_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_PUBLIC_t type,
+ const TPMU_PUBLIC_ID_t *p)
+{
+ switch(type)
+ {
+ case TPM_ALG_KEYEDHASH:
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->keyedHash.size, p->keyedHash.buffer);
+ break;
+ case TPM_ALG_SYMCIPHER:
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->sym.size, p->sym.buffer);
+ break;
+ case TPM_ALG_RSA:
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->rsa.size, p->rsa.buffer);
+ break;
+ case TPM_ALG_ECC:
+ grub_Tss2_MU_TPMS_ECC_POINT_Marshal (buffer, &p->ecc);
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_PUBLIC_PARMS_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->type);
+ grub_Tss2_MU_TPMU_PUBLIC_PARMS_Marshal (buffer, p->type, &p->parameters);
+}
+
+void
+grub_Tss2_MU_TPMT_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_PUBLIC_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->type);
+ grub_tpm2_buffer_pack_u16 (buffer, p->nameAlg);
+ grub_Tss2_MU_TPMA_OBJECT_Marshal (buffer, &p->objectAttributes);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->authPolicy.size, p->authPolicy.buffer);
+ grub_Tss2_MU_TPMU_PUBLIC_PARMS_Marshal (buffer, p->type, &p->parameters);
+ grub_Tss2_MU_TPMU_PUBLIC_ID_Marshal (buffer, p->type, &p->unique);
+}
+
+void
+grub_Tss2_MU_TPM2B_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_PUBLIC_t *p)
+{
+ grub_uint32_t start;
+ grub_uint16_t size;
+
+ if (p)
+ {
+ grub_tpm2_buffer_pack_u16 (buffer, p->size);
+
+ start = buffer->size;
+ grub_Tss2_MU_TPMT_PUBLIC_Marshal (buffer, &p->publicArea);
+ size = grub_cpu_to_be16 (buffer->size - start);
+ grub_memcpy (&buffer->data[start - sizeof (grub_uint16_t)], &size, sizeof (size));
+ }
+ else
+ grub_tpm2_buffer_pack_u16 (buffer, 0);
+}
+
+void
+grub_Tss2_MU_TPMS_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SENSITIVE_CREATE_t *p)
+{
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->userAuth.size, p->userAuth.buffer);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->data.size, p->data.buffer);
+}
+
+void
+grub_Tss2_MU_TPMU_SENSITIVE_COMPOSITE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_PUBLIC_t type,
+ const TPMU_SENSITIVE_COMPOSITE_t *p)
+{
+ switch(type)
+ {
+ case TPM_ALG_RSA:
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->rsa.size, p->rsa.buffer);
+ break;
+ case TPM_ALG_ECC:
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->ecc.size, p->ecc.buffer);
+ break;
+ case TPM_ALG_KEYEDHASH:
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->bits.size, p->bits.buffer);
+ break;
+ case TPM_ALG_SYMCIPHER:
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->sym.size, p->sym.buffer);
+ break;
+ default:
+ buffer->error = 1;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_SENSITIVE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SENSITIVE_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->sensitiveType);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->authValue.size, p->authValue.buffer);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->seedValue.size, p->seedValue.buffer);
+ grub_Tss2_MU_TPMU_SENSITIVE_COMPOSITE_Marshal (buffer, p->sensitiveType, &p->sensitive);
+}
+
+void
+grub_Tss2_MU_TPM2B_SENSITIVE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_SENSITIVE_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->size);
+ grub_Tss2_MU_TPMT_SENSITIVE_Marshal (buffer, &p->sensitiveArea);
+}
+
+void
+grub_Tss2_MU_TPM2B_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_SENSITIVE_CREATE_t *sensitiveCreate)
+{
+ grub_uint32_t start;
+ grub_uint16_t size;
+
+ if (sensitiveCreate)
+ {
+ grub_tpm2_buffer_pack_u16 (buffer, sensitiveCreate->size);
+ start = buffer->size;
+ grub_Tss2_MU_TPMS_SENSITIVE_CREATE_Marshal (buffer, &sensitiveCreate->sensitive);
+ size = grub_cpu_to_be16 (buffer->size - start);
+
+ grub_memcpy (&buffer->data[start - sizeof (grub_uint16_t)], &size, sizeof (size));
+ }
+ else
+ grub_tpm2_buffer_pack_u16 (buffer, 0);
+}
+
+void
+grub_Tss2_MU_TPMS_SIGNATURE_RSA_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SIGNATURE_RSA_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->hash);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->sig.size, p->sig.buffer);
+}
+
+void
+grub_Tss2_MU_TPMS_SIGNATURE_ECC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SIGNATURE_ECC_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->hash);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->signatureR.size, p->signatureR.buffer);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->signatureS.size, p->signatureS.buffer);
+}
+
+void
+grub_Tss2_MU_TPMU_HA_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_HASH_t hashAlg,
+ const TPMU_HA_t *p)
+{
+ grub_uint16_t i;
+
+ switch (hashAlg)
+ {
+ case TPM_ALG_SHA1:
+ for (i = 0; i < TPM_SHA1_DIGEST_SIZE; i++)
+ grub_tpm2_buffer_pack_u8 (buffer, p->sha1[i]);
+ break;
+ case TPM_ALG_SHA256:
+ for (i = 0; i < TPM_SHA256_DIGEST_SIZE; i++)
+ grub_tpm2_buffer_pack_u8 (buffer, p->sha256[i]);
+ break;
+ case TPM_ALG_SHA384:
+ for (i = 0; i < TPM_SHA384_DIGEST_SIZE; i++)
+ grub_tpm2_buffer_pack_u8 (buffer, p->sha384[i]);
+ break;
+ case TPM_ALG_SHA512:
+ for (i = 0; i < TPM_SHA512_DIGEST_SIZE; i++)
+ grub_tpm2_buffer_pack_u8 (buffer, p->sha512[i]);
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_HA_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_HA_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->hashAlg);
+ grub_Tss2_MU_TPMU_HA_Marshal (buffer, p->hashAlg, &p->digest);
+}
+
+void
+grub_Tss2_MU_TPMU_SIGNATURE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_SIG_SCHEME_t sigAlg,
+ const TPMU_SIGNATURE_t *p)
+{
+ switch (sigAlg)
+ {
+ case TPM_ALG_RSASSA:
+ grub_Tss2_MU_TPMS_SIGNATURE_RSA_Marshal (buffer, (TPMS_SIGNATURE_RSA_t *) &p->rsassa);
+ break;
+ case TPM_ALG_RSAPSS:
+ grub_Tss2_MU_TPMS_SIGNATURE_RSA_Marshal (buffer, (TPMS_SIGNATURE_RSA_t *) &p->rsapss);
+ break;
+ case TPM_ALG_ECDSA:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Marshal (buffer, (TPMS_SIGNATURE_ECC_t *) &p->ecdsa);
+ break;
+ case TPM_ALG_ECDAA:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Marshal (buffer, (TPMS_SIGNATURE_ECC_t *) &p->ecdaa);
+ break;
+ case TPM_ALG_SM2:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Marshal (buffer, (TPMS_SIGNATURE_ECC_t *) &p->sm2);
+ break;
+ case TPM_ALG_ECSCHNORR:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Marshal (buffer, (TPMS_SIGNATURE_ECC_t *) &p->ecschnorr);
+ break;
+ case TPM_ALG_HMAC:
+ grub_Tss2_MU_TPMT_HA_Marshal (buffer, &p->hmac);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_SIGNATURE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SIGNATURE_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->sigAlg);
+ grub_Tss2_MU_TPMU_SIGNATURE_Marshal (buffer, p->sigAlg, &p->signature);
+}
+
+void
+grub_Tss2_MU_TPMT_TK_VERIFIED_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_TK_VERIFIED_t *p)
+{
+ grub_tpm2_buffer_pack_u16 (buffer, p->tag);
+ grub_tpm2_buffer_pack_u32 (buffer, p->hierarchy);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->digest.size, p->digest.buffer);
+}
+
+static void
+__Tss2_MU_TPM2B_BUFFER_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_t *p, grub_uint16_t bound)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->size);
+
+ if (p->size > bound)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ grub_tpm2_buffer_unpack (buffer, &p->buffer, p->size);
+}
+
+#define TPM2B_BUFFER_UNMARSHAL(buffer, type, data) \
+ __Tss2_MU_TPM2B_BUFFER_Unmarshal(buffer, (TPM2B_t *)data, sizeof(type) - sizeof(grub_uint16_t))
+
+void
+grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_AUTH_RESPONSE_t *p)
+{
+ grub_uint8_t tmp;
+ grub_uint32_t tmp32;
+
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->nonce.size);
+
+ if (p->nonce.size)
+ grub_tpm2_buffer_unpack (buffer, &p->nonce.buffer, p->nonce.size);
+
+ grub_tpm2_buffer_unpack_u8 (buffer, &tmp);
+ tmp32 = tmp;
+ grub_memcpy (&p->sessionAttributes, &tmp32, sizeof (grub_uint32_t));
+
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->hmac.size);
+
+ if (p->hmac.size)
+ grub_tpm2_buffer_unpack (buffer, &p->hmac.buffer, p->hmac.size);
+}
+
+void
+grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_DIGEST_t *digest)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_DIGEST_t, digest);
+}
+
+void
+grub_Tss2_MU_TPM2B_NONCE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_NONCE_t *nonce)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_NONCE_t, nonce);
+}
+
+void
+grub_Tss2_MU_TPM2B_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_DATA_t *data)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_DATA_t, data);
+}
+
+void
+grub_Tss2_MU_TPMS_CREATION_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_CREATION_DATA_t *data)
+{
+ grub_Tss2_MU_TPML_PCR_SELECTION_Unmarshal (buffer, &data->pcrSelect);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &data->pcrDigest);
+ grub_tpm2_buffer_unpack_u8 (buffer, (grub_uint8_t *)&data->locality);
+ grub_tpm2_buffer_unpack_u16 (buffer, &data->parentNameAlg);
+ grub_Tss2_MU_TPM2B_NAME_Unmarshal (buffer, &data->parentName);
+ grub_Tss2_MU_TPM2B_NAME_Unmarshal (buffer, &data->parentQualifiedName);
+ grub_Tss2_MU_TPM2B_DATA_Unmarshal (buffer, &data->outsideInfo);
+}
+
+void
+grub_Tss2_MU_TPM2B_CREATION_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_CREATION_DATA_t *data)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &data->size);
+ grub_Tss2_MU_TPMS_CREATION_DATA_Unmarshal (buffer, &data->creationData);
+}
+
+void
+grub_Tss2_MU_TPM2B_PRIVATE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_PRIVATE_t *private)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_PRIVATE_t, private);
+}
+
+void
+grub_Tss2_MU_TPM2B_SENSITIVE_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_SENSITIVE_DATA_t *data)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_SENSITIVE_DATA_t, data);
+}
+
+void
+grub_Tss2_MU_TPM2B_PUBLIC_KEY_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_PUBLIC_KEY_RSA_t *rsa)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_PUBLIC_KEY_RSA_t, rsa);
+}
+
+void
+grub_Tss2_MU_TPM2B_ECC_PARAMETER_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_ECC_PARAMETER_t *param)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_ECC_PARAMETER_t, param);
+}
+
+void
+grub_Tss2_MU_TPMA_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMA_OBJECT_t *p)
+{
+ grub_tpm2_buffer_unpack_u32 (buffer, (grub_uint32_t *) p);
+}
+
+void
+grub_Tss2_MU_TPMS_SCHEME_HMAC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SCHEME_HMAC_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->hashAlg);
+}
+
+void
+grub_Tss2_MU_TPMS_SCHEME_XOR_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SCHEME_XOR_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->hashAlg);
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf);
+}
+
+void
+grub_Tss2_MU_TPMU_SCHEME_KEYEDHASH_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_KEYEDHASH_SCHEME_t scheme,
+ TPMU_SCHEME_KEYEDHASH_t *p)
+{
+ switch (scheme)
+ {
+ case TPM_ALG_HMAC:
+ grub_Tss2_MU_TPMS_SCHEME_HMAC_Unmarshal (buffer, &p->hmac);
+ break;
+ case TPM_ALG_XOR:
+ grub_Tss2_MU_TPMS_SCHEME_XOR_Unmarshal (buffer, &p->exclusiveOr);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_KEYEDHASH_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_KEYEDHASH_SCHEME_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme);
+ grub_Tss2_MU_TPMU_SCHEME_KEYEDHASH_Unmarshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMS_KEYEDHASH_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_KEYEDHASH_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_KEYEDHASH_SCHEME_Unmarshal (buffer, &p->scheme);
+}
+
+void
+grub_Tss2_MU_TPMU_SYM_KEY_BITS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_SYM_OBJECT_t algorithm,
+ TPMU_SYM_KEY_BITS_t *p)
+{
+ switch (algorithm)
+ {
+ case TPM_ALG_AES:
+ case TPM_ALG_SM4:
+ case TPM_ALG_CAMELLIA:
+ case TPM_ALG_XOR:
+ grub_tpm2_buffer_unpack_u16 (buffer, (grub_uint16_t *) p);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMU_SYM_MODE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_SYM_OBJECT_t algorithm,
+ TPMU_SYM_MODE_t *p)
+{
+ switch (algorithm)
+ {
+ case TPM_ALG_AES:
+ case TPM_ALG_SM4:
+ case TPM_ALG_CAMELLIA:
+ grub_tpm2_buffer_unpack_u16 (buffer, (grub_uint16_t *) p);
+ break;
+ case TPM_ALG_XOR:
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_SYM_DEF_OBJECT_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->algorithm);
+ grub_Tss2_MU_TPMU_SYM_KEY_BITS_Unmarshal (buffer, p->algorithm, &p->keyBits);
+ grub_Tss2_MU_TPMU_SYM_MODE_Unmarshal (buffer, p->algorithm, &p->mode);
+}
+
+void
+grub_Tss2_MU_TPMS_SYMCIPHER_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SYMCIPHER_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->sym);
+}
+
+void
+grub_Tss2_MU_TPMU_ASYM_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_RSA_DECRYPT_t scheme,
+ TPMU_ASYM_SCHEME_t *p __attribute__((unused)))
+{
+ switch (scheme)
+ {
+ case TPM_ALG_NULL:
+ break;
+ default:
+ /* Unsupported */
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_RSA_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_RSA_SCHEME_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme);
+ grub_Tss2_MU_TPMU_ASYM_SCHEME_Unmarshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMS_RSA_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_RSA_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->symmetric);
+ grub_Tss2_MU_TPMT_RSA_SCHEME_Unmarshal (buffer, &p->scheme);
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->keyBits);
+ grub_tpm2_buffer_unpack_u32 (buffer, &p->exponent);
+}
+
+void
+grub_Tss2_MU_TPMT_ECC_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_ECC_SCHEME_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme);
+ grub_Tss2_MU_TPMU_ASYM_SCHEME_Unmarshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMU_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_KDF_t scheme,
+ TPMU_KDF_SCHEME_t *p)
+{
+ switch (scheme)
+ {
+ case TPM_ALG_MGF1:
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->mgf1.hashAlg);
+ break;
+ case TPM_ALG_KDF1_SP800_56A:
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf1_sp800_56a.hashAlg);
+ break;
+ case TPM_ALG_KDF2:
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf2.hashAlg);
+ break;
+ case TPM_ALG_KDF1_SP800_108:
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->kdf1_sp800_108.hashAlg);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_KDF_SCHEME_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->scheme);
+ grub_Tss2_MU_TPMU_KDF_SCHEME_Unmarshal (buffer, p->scheme, &p->details);
+}
+
+void
+grub_Tss2_MU_TPMS_ECC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_ECC_PARMS_t *p)
+{
+ grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Unmarshal (buffer, &p->symmetric);
+ grub_Tss2_MU_TPMT_ECC_SCHEME_Unmarshal (buffer, &p->scheme );
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->curveID);
+ grub_Tss2_MU_TPMT_KDF_SCHEME_Unmarshal (buffer, &p->kdf);
+}
+
+void
+grub_Tss2_MU_TPMU_PUBLIC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ grub_uint32_t type,
+ TPMU_PUBLIC_PARMS_t *p)
+{
+ switch (type)
+ {
+ case TPM_ALG_KEYEDHASH:
+ grub_Tss2_MU_TPMS_KEYEDHASH_PARMS_Unmarshal (buffer, &p->keyedHashDetail);
+ break;
+ case TPM_ALG_SYMCIPHER:
+ grub_Tss2_MU_TPMS_SYMCIPHER_PARMS_Unmarshal (buffer, &p->symDetail);
+ break;
+ case TPM_ALG_RSA:
+ grub_Tss2_MU_TPMS_RSA_PARMS_Unmarshal (buffer, &p->rsaDetail);
+ break;
+ case TPM_ALG_ECC:
+ grub_Tss2_MU_TPMS_ECC_PARMS_Unmarshal (buffer, &p->eccDetail);
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMS_ECC_POINT_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_ECC_POINT_t *p)
+{
+ grub_Tss2_MU_TPM2B_ECC_PARAMETER_Unmarshal (buffer, &p->x);
+ grub_Tss2_MU_TPM2B_ECC_PARAMETER_Unmarshal (buffer, &p->y);
+}
+
+void
+grub_Tss2_MU_TPMU_PUBLIC_ID_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_PUBLIC_t type,
+ TPMU_PUBLIC_ID_t *p)
+{
+ switch(type)
+ {
+ case TPM_ALG_KEYEDHASH:
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &p->keyedHash);
+ break;
+ case TPM_ALG_SYMCIPHER:
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &p->sym);
+ break;
+ case TPM_ALG_RSA:
+ grub_Tss2_MU_TPM2B_PUBLIC_KEY_RSA_Unmarshal (buffer, &p->rsa);
+ break;
+ case TPM_ALG_ECC:
+ grub_Tss2_MU_TPMS_ECC_POINT_Unmarshal (buffer, &p->ecc);
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_PUBLIC_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->type);
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->nameAlg);
+ grub_Tss2_MU_TPMA_OBJECT_Unmarshal (buffer, &p->objectAttributes);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &p->authPolicy);
+ grub_Tss2_MU_TPMU_PUBLIC_PARMS_Unmarshal (buffer, p->type, &p->parameters);
+ grub_Tss2_MU_TPMU_PUBLIC_ID_Unmarshal (buffer, p->type, &p->unique);
+}
+
+void
+grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_PUBLIC_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->size);
+ grub_Tss2_MU_TPMT_PUBLIC_Unmarshal (buffer, &p->publicArea);
+}
+
+void
+grub_Tss2_MU_TPMS_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_NV_PUBLIC_t *p)
+{
+ grub_tpm2_buffer_unpack_u32 (buffer, &p->nvIndex);
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->nameAlg);
+ grub_tpm2_buffer_unpack_u32 (buffer, &p->attributes);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &p->authPolicy);
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->dataSize);
+}
+
+void
+grub_Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_NV_PUBLIC_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->size);
+ grub_Tss2_MU_TPMS_NV_PUBLIC_Unmarshal (buffer, &p->nvPublic);
+}
+
+void
+grub_Tss2_MU_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_NAME_t *n)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_NAME_t, n);
+}
+
+void
+grub_Tss2_MU_TPMS_TAGGED_PROPERTY_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_TAGGED_PROPERTY_t *property)
+{
+ grub_tpm2_buffer_unpack_u32 (buffer, &property->property);
+ grub_tpm2_buffer_unpack_u32 (buffer, &property->value);
+}
+
+void
+grub_Tss2_MU_TPMT_TK_CREATION_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_TK_CREATION_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->tag);
+ grub_tpm2_buffer_unpack_u32 (buffer, &p->hierarchy);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &p->digest);
+}
+
+void
+grub_Tss2_MU_TPMT_TK_HASHCHECK_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_TK_HASHCHECK_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->tag);
+ grub_tpm2_buffer_unpack_u32 (buffer, &p->hierarchy);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &p->digest);
+}
+
+void
+grub_Tss2_MU_TPMT_TK_VERIFIED_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_TK_VERIFIED_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->tag);
+ grub_tpm2_buffer_unpack_u32 (buffer, &p->hierarchy);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &p->digest);
+}
+
+void
+grub_Tss2_MU_TPMS_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_PCR_SELECTION_t *pcrSelection)
+{
+ grub_uint32_t i;
+
+ grub_tpm2_buffer_unpack_u16 (buffer, &pcrSelection->hash);
+ grub_tpm2_buffer_unpack_u8 (buffer, &pcrSelection->sizeOfSelect);
+
+ if (pcrSelection->sizeOfSelect > TPM_PCR_SELECT_MAX)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ for (i = 0; i < pcrSelection->sizeOfSelect; i++)
+ grub_tpm2_buffer_unpack_u8 (buffer, &pcrSelection->pcrSelect[i]);
+}
+
+void
+grub_Tss2_MU_TPML_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPML_PCR_SELECTION_t *pcrSelection)
+{
+ grub_uint32_t i;
+
+ grub_tpm2_buffer_unpack_u32 (buffer, &pcrSelection->count);
+
+ if (pcrSelection->count > TPM_NUM_PCR_BANKS)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ for (i = 0; i < pcrSelection->count; i++)
+ grub_Tss2_MU_TPMS_PCR_SELECTION_Unmarshal (buffer, &pcrSelection->pcrSelections[i]);
+}
+
+void
+grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPML_DIGEST_t *digest)
+{
+ grub_uint32_t i;
+
+ grub_tpm2_buffer_unpack_u32 (buffer, &digest->count);
+
+ if (digest->count > 8)
+ {
+ buffer->error = 1;
+ return;
+ }
+
+ for (i = 0; i < digest->count; i++)
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (buffer, &digest->digests[i]);
+}
+
+void
+grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SIGNATURE_RSA_t *rsa)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &rsa->hash);
+ grub_Tss2_MU_TPM2B_PUBLIC_KEY_RSA_Unmarshal (buffer, &rsa->sig);
+}
+
+void
+grub_Tss2_MU_TPMS_SIGNATURE_ECC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SIGNATURE_ECC_t *ecc)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &ecc->hash);
+ grub_Tss2_MU_TPM2B_ECC_PARAMETER_Unmarshal (buffer, &ecc->signatureR);
+ grub_Tss2_MU_TPM2B_ECC_PARAMETER_Unmarshal (buffer, &ecc->signatureS);
+}
+
+void
+grub_Tss2_MU_TPMU_HA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_HASH_t hashAlg,
+ TPMU_HA_t *p)
+{
+ switch (hashAlg)
+ {
+ case TPM_ALG_SHA1:
+ grub_tpm2_buffer_unpack (buffer, &p->sha1, TPM_SHA1_DIGEST_SIZE);
+ break;
+ case TPM_ALG_SHA256:
+ grub_tpm2_buffer_unpack (buffer, &p->sha256, TPM_SHA256_DIGEST_SIZE);
+ break;
+ case TPM_ALG_SHA384:
+ grub_tpm2_buffer_unpack (buffer, &p->sha384, TPM_SHA384_DIGEST_SIZE);
+ break;
+ case TPM_ALG_SHA512:
+ grub_tpm2_buffer_unpack (buffer, &p->sha512, TPM_SHA512_DIGEST_SIZE);
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_HA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_HA_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->hashAlg);
+ grub_Tss2_MU_TPMU_HA_Unmarshal (buffer, p->hashAlg, &p->digest);
+}
+
+void
+grub_Tss2_MU_TPMU_SIGNATURE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_SIG_SCHEME_t sigAlg,
+ TPMU_SIGNATURE_t *p)
+{
+ switch (sigAlg)
+ {
+ case TPM_ALG_RSASSA:
+ grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (buffer, (TPMS_SIGNATURE_RSA_t *)&p->rsassa);
+ break;
+ case TPM_ALG_RSAPSS:
+ grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (buffer, (TPMS_SIGNATURE_RSA_t *)&p->rsapss);
+ break;
+ case TPM_ALG_ECDSA:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Unmarshal (buffer, (TPMS_SIGNATURE_ECC_t *)&p->ecdsa);
+ break;
+ case TPM_ALG_ECDAA:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Unmarshal (buffer, (TPMS_SIGNATURE_ECC_t *)&p->ecdaa);
+ break;
+ case TPM_ALG_SM2:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Unmarshal (buffer, (TPMS_SIGNATURE_ECC_t *)&p->sm2);
+ break;
+ case TPM_ALG_ECSCHNORR:
+ grub_Tss2_MU_TPMS_SIGNATURE_ECC_Unmarshal (buffer, (TPMS_SIGNATURE_ECC_t *)&p->ecschnorr);
+ break;
+ case TPM_ALG_HMAC:
+ grub_Tss2_MU_TPMT_HA_Unmarshal (buffer, &p->hmac);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ buffer->error = 1;
+ break;
+ }
+}
+
+void
+grub_Tss2_MU_TPMT_SIGNATURE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_SIGNATURE_t *p)
+{
+ grub_tpm2_buffer_unpack_u16 (buffer, &p->sigAlg);
+ grub_Tss2_MU_TPMU_SIGNATURE_Unmarshal (buffer, p->sigAlg, &p->signature);
+}
diff --git a/grub-core/lib/tss2/tss2_mu.h b/grub-core/lib/tss2/tss2_mu.h
new file mode 100644
index 000000000..8f82126e1
--- /dev/null
+++ b/grub-core/lib/tss2/tss2_mu.h
@@ -0,0 +1,397 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_MU_HEADER
+#define GRUB_TPM2_MU_HEADER 1
+
+#include <tss2_buffer.h>
+#include <tss2_structs.h>
+
+extern void
+grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_AUTH_COMMAND_t *authCommand);
+
+extern void
+grub_Tss2_MU_TPM2B_Marshal (grub_tpm2_buffer_t buffer,
+ const grub_uint16_t size,
+ const grub_uint8_t *b);
+
+extern void
+grub_Tss2_MU_TPMU_SYM_KEY_BITS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_SYM_OBJECT_t algorithm,
+ const TPMU_SYM_KEY_BITS_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_SYM_MODE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_SYM_OBJECT_t algorithm,
+ const TPMU_SYM_MODE_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_SYM_DEF_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SYM_DEF_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_PCR_SELECTION_t *pcrSelection);
+
+extern void
+grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (grub_tpm2_buffer_t buffer,
+ const TPML_PCR_SELECTION_t *pcrSelection);
+
+extern void
+grub_Tss2_MU_TPMA_OBJECT_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMA_OBJECT_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SCHEME_XOR_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SCHEME_XOR_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SCHEME_HMAC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SCHEME_HMAC_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_SCHEME_KEYEDHASH_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_KEYEDHASH_SCHEME_t scheme,
+ const TPMU_SCHEME_KEYEDHASH_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_KEYEDHASH_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_KEYEDHASH_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_KEYEDHASH_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_KEYEDHASH_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SYM_DEF_OBJECT_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_ASYM_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_RSA_DECRYPT_t scheme,
+ const TPMU_ASYM_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_RSA_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_RSA_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_RSA_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_RSA_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SYMCIPHER_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SYMCIPHER_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_ECC_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_ECC_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_KDF_t scheme,
+ const TPMU_KDF_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_KDF_SCHEME_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_KDF_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_ECC_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_ECC_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const grub_uint32_t type,
+ const TPMU_PUBLIC_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_ECC_POINT_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_ECC_POINT_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_PUBLIC_ID_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_PUBLIC_t type,
+ const TPMU_PUBLIC_ID_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_PUBLIC_PARMS_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_PUBLIC_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_PUBLIC_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_PUBLIC_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SENSITIVE_CREATE_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_SENSITIVE_CREATE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_SENSITIVE_CREATE_t *sensitiveCreate);
+
+extern void
+grub_Tss2_MU_TPMU_SENSITIVE_COMPOSITE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_PUBLIC_t type,
+ const TPMU_SENSITIVE_COMPOSITE_t *p);
+extern void
+grub_Tss2_MU_TPMT_SENSITIVE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SENSITIVE_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_SENSITIVE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_SENSITIVE_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SIGNATURE_RSA_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SIGNATURE_RSA_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SIGNATURE_ECC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_SIGNATURE_ECC_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_HA_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_HASH_t hashAlg,
+ const TPMU_HA_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_HA_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_HA_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_SIGNATURE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMI_ALG_SIG_SCHEME_t sigAlg,
+ const TPMU_SIGNATURE_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_SIGNATURE_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_SIGNATURE_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_TK_VERIFIED_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMT_TK_VERIFIED_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_AUTH_RESPONSE_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_DIGEST_t *digest);
+
+extern void
+grub_Tss2_MU_TPM2B_NONCE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_NONCE_t *nonce);
+
+extern void
+grub_Tss2_MU_TPM2B_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_DATA_t *data);
+
+extern void
+grub_Tss2_MU_TPMS_CREATION_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_CREATION_DATA_t *data);
+
+extern void
+grub_Tss2_MU_TPM2B_CREATION_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_CREATION_DATA_t *data);
+
+extern void
+grub_Tss2_MU_TPM2B_PRIVATE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_PRIVATE_t *private);
+
+extern void
+grub_Tss2_MU_TPM2B_SENSITIVE_DATA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_SENSITIVE_DATA_t *data);
+
+extern void
+grub_Tss2_MU_TPM2B_PUBLIC_KEY_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_PUBLIC_KEY_RSA_t *rsa);
+
+extern void
+grub_Tss2_MU_TPM2B_ECC_PARAMETER_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_ECC_PARAMETER_t *param);
+
+extern void
+grub_Tss2_MU_TPMA_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMA_OBJECT_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SCHEME_HMAC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SCHEME_HMAC_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SCHEME_XOR_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SCHEME_XOR_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_SCHEME_KEYEDHASH_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_KEYEDHASH_SCHEME_t scheme,
+ TPMU_SCHEME_KEYEDHASH_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_KEYEDHASH_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_KEYEDHASH_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_KEYEDHASH_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_KEYEDHASH_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_SYM_KEY_BITS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_SYM_OBJECT_t algorithm,
+ TPMU_SYM_KEY_BITS_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_SYM_MODE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_SYM_OBJECT_t algorithm,
+ TPMU_SYM_MODE_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_SYM_DEF_OBJECT_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_SYM_DEF_OBJECT_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SYMCIPHER_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SYMCIPHER_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_ASYM_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_RSA_DECRYPT_t scheme,
+ TPMU_ASYM_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_RSA_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_RSA_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_RSA_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_RSA_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_ECC_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_ECC_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_KDF_t scheme,
+ TPMU_KDF_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_KDF_SCHEME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_KDF_SCHEME_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_ECC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_ECC_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_PUBLIC_PARMS_Unmarshal (grub_tpm2_buffer_t buffer,
+ grub_uint32_t type,
+ TPMU_PUBLIC_PARMS_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_ECC_POINT_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_ECC_POINT_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_PUBLIC_ID_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_PUBLIC_t type,
+ TPMU_PUBLIC_ID_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_PUBLIC_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_PUBLIC_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_NV_PUBLIC_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_NV_PUBLIC_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_NAME_t *n);
+
+extern void
+grub_Tss2_MU_TPMS_TAGGED_PROPERTY_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_TAGGED_PROPERTY_t *property);
+
+extern void
+grub_Tss2_MU_TPMT_TK_CREATION_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_TK_CREATION_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_TK_HASHCHECK_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_TK_HASHCHECK_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_TK_VERIFIED_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_TK_VERIFIED_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_PCR_SELECTION_t *pcrSelection);
+
+extern void
+grub_Tss2_MU_TPML_PCR_SELECTION_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPML_PCR_SELECTION_t *pcrSelection);
+
+extern void
+grub_Tss2_MU_TPML_DIGEST_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPML_DIGEST_t *digest);
+
+extern void
+grub_Tss2_MU_TPMS_SIGNATURE_RSA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SIGNATURE_RSA_t *p);
+
+extern void
+grub_Tss2_MU_TPMS_SIGNATURE_ECC_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMS_SIGNATURE_ECC_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_HA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_HASH_t hashAlg,
+ TPMU_HA_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_HA_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_HA_t *p);
+
+extern void
+grub_Tss2_MU_TPMU_SIGNATURE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMI_ALG_SIG_SCHEME_t sigAlg,
+ TPMU_SIGNATURE_t *p);
+
+extern void
+grub_Tss2_MU_TPMT_SIGNATURE_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPMT_SIGNATURE_t *p);
+
+#endif /* ! GRUB_TPM2_MU_HEADER */
diff --git a/grub-core/lib/tss2/tss2_structs.h b/grub-core/lib/tss2/tss2_structs.h
new file mode 100644
index 000000000..3f6ace3f9
--- /dev/null
+++ b/grub-core/lib/tss2/tss2_structs.h
@@ -0,0 +1,773 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_INTERNAL_STRUCTS_HEADER
+#define GRUB_TPM2_INTERNAL_STRUCTS_HEADER 1
+
+#include <tss2_types.h>
+
+/* TPMS_TAGGED_PROPERTY Structure */
+struct TPMS_TAGGED_PROPERTY
+{
+ TPM_PT_t property;
+ grub_uint32_t value;
+};
+typedef struct TPMS_TAGGED_PROPERTY TPMS_TAGGED_PROPERTY_t;
+
+/* TPML_TAGGED_TPM_PROPERTY Structure */
+struct TPML_TAGGED_TPM_PROPERTY
+{
+ grub_uint32_t count;
+ TPMS_TAGGED_PROPERTY_t tpmProperty[TPM_MAX_TPM_PROPERTIES];
+};
+typedef struct TPML_TAGGED_TPM_PROPERTY TPML_TAGGED_TPM_PROPERTY_t;
+
+/* TPMU_CAPABILITIES Structure */
+union TPMU_CAPABILITIES
+{
+ TPML_TAGGED_TPM_PROPERTY_t tpmProperties;
+};
+typedef union TPMU_CAPABILITIES TPMU_CAPABILITIES_t;
+
+/* TPMS_CAPABILITY_DATA Structure */
+struct TPMS_CAPABILITY_DATA
+{
+ TPM_CAP_t capability;
+ TPMU_CAPABILITIES_t data;
+};
+typedef struct TPMS_CAPABILITY_DATA TPMS_CAPABILITY_DATA_t;
+
+/* TPMS_PCR_SELECT Structure */
+struct TPMS_PCR_SELECT
+{
+ grub_uint8_t sizeOfSelect;
+ grub_uint8_t pcrSelect[TPM_PCR_SELECT_MAX];
+};
+typedef struct TPMS_PCR_SELECT TPMS_PCR_SELECT_t;
+
+/* TPMS_PCR_SELECTION Structure */
+struct TPMS_PCR_SELECTION
+{
+ TPMI_ALG_HASH_t hash;
+ grub_uint8_t sizeOfSelect;
+ grub_uint8_t pcrSelect[TPM_PCR_SELECT_MAX];
+};
+typedef struct TPMS_PCR_SELECTION TPMS_PCR_SELECTION_t;
+
+static inline void TPMS_PCR_SELECTION_SelectPCR(TPMS_PCR_SELECTION_t *self, grub_uint32_t n)
+{
+ self->pcrSelect[(n / 8)] |= (1 << (n % 8));
+}
+
+/* TPML_PCR_SELECTION Structure */
+struct TPML_PCR_SELECTION
+{
+ grub_uint32_t count;
+ TPMS_PCR_SELECTION_t pcrSelections[TPM_NUM_PCR_BANKS];
+};
+typedef struct TPML_PCR_SELECTION TPML_PCR_SELECTION_t;
+
+/* TPMU_HA Structure */
+union TPMU_HA
+{
+ grub_uint8_t sha1[TPM_SHA1_DIGEST_SIZE];
+ grub_uint8_t sha256[TPM_SHA256_DIGEST_SIZE];
+ grub_uint8_t sha384[TPM_SHA384_DIGEST_SIZE];
+ grub_uint8_t sha512[TPM_SHA512_DIGEST_SIZE];
+ grub_uint8_t sm3_256[TPM_SM3_256_DIGEST_SIZE];
+};
+typedef union TPMU_HA TPMU_HA_t;
+
+/* TPM2B Structure */
+struct TPM2B
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[1];
+};
+typedef struct TPM2B TPM2B_t;
+
+/* TPM2B_DIGEST Structure */
+struct TPM2B_DIGEST
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[sizeof(TPMU_HA_t)];
+};
+typedef struct TPM2B_DIGEST TPM2B_DIGEST_t;
+
+/* TPML_DIGEST Structure */
+struct TPML_DIGEST
+{
+ grub_uint32_t count;
+ TPM2B_DIGEST_t digests[8];
+};
+typedef struct TPML_DIGEST TPML_DIGEST_t;
+
+/* TPM2B_NONCE Type */
+typedef TPM2B_DIGEST_t TPM2B_NONCE_t;
+
+/* TPMA_SESSION Structure */
+struct TPMA_SESSION
+{
+ grub_uint8_t continueSession:1;
+ grub_uint8_t auditExclusive:1;
+ grub_uint8_t auditReset:1;
+ grub_uint8_t reserved:2;
+ grub_uint8_t decrypt:1;
+ grub_uint8_t encrypt:1;
+ grub_uint8_t audit:1;
+};
+typedef struct TPMA_SESSION TPMA_SESSION_t;
+
+/* TPM2B_AUTH Type */
+typedef TPM2B_DIGEST_t TPM2B_AUTH_t;
+
+/* TPMS_AUTH_COMMAND Structure */
+struct TPMS_AUTH_COMMAND
+{
+ TPMI_SH_AUTH_SESSION_t sessionHandle;
+ TPM2B_NONCE_t nonce;
+ TPMA_SESSION_t sessionAttributes;
+ TPM2B_AUTH_t hmac;
+};
+typedef struct TPMS_AUTH_COMMAND TPMS_AUTH_COMMAND_t;
+
+/* TPMS_AUTH_RESPONSE Structure */
+struct TPMS_AUTH_RESPONSE
+{
+ TPM2B_NONCE_t nonce;
+ TPMA_SESSION_t sessionAttributes;
+ TPM2B_AUTH_t hmac;
+};
+typedef struct TPMS_AUTH_RESPONSE TPMS_AUTH_RESPONSE_t;
+
+/* TPM2B_SENSITIVE_DATA Structure */
+struct TPM2B_SENSITIVE_DATA
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_MAX_SYM_DATA];
+};
+typedef struct TPM2B_SENSITIVE_DATA TPM2B_SENSITIVE_DATA_t;
+
+/* TPMS_SENSITIVE_CREATE Structure */
+struct TPMS_SENSITIVE_CREATE
+{
+ TPM2B_AUTH_t userAuth;
+ TPM2B_SENSITIVE_DATA_t data;
+};
+typedef struct TPMS_SENSITIVE_CREATE TPMS_SENSITIVE_CREATE_t;
+
+/* TPM2B_SENSITIVE_CREATE Structure */
+struct TPM2B_SENSITIVE_CREATE
+{
+ grub_uint16_t size;
+ TPMS_SENSITIVE_CREATE_t sensitive;
+};
+typedef struct TPM2B_SENSITIVE_CREATE TPM2B_SENSITIVE_CREATE_t;
+
+/* TPMA_OBJECT Structure */
+struct TPMA_OBJECT
+{
+ grub_uint32_t reserved1:1;
+ grub_uint32_t fixedTPM:1;
+ grub_uint32_t stClear:1;
+ grub_uint32_t reserved2:1;
+ grub_uint32_t fixedParent:1;
+ grub_uint32_t sensitiveDataOrigin:1;
+ grub_uint32_t userWithAuth:1;
+ grub_uint32_t adminWithPolicy:1;
+ grub_uint32_t reserved3:2;
+ grub_uint32_t noDA:1;
+ grub_uint32_t encryptedDuplication:1;
+ grub_uint32_t reserved4:4;
+ grub_uint32_t restricted:1;
+ grub_uint32_t decrypt:1;
+ grub_uint32_t sign:1;
+ grub_uint32_t reserved5:13;
+};
+typedef struct TPMA_OBJECT TPMA_OBJECT_t;
+
+/* TPMS_SCHEME_HASH Structure */
+struct TPMS_SCHEME_HASH
+{
+ TPMI_ALG_HASH_t hashAlg;
+};
+typedef struct TPMS_SCHEME_HASH TPMS_SCHEME_HASH_t;
+
+/* TPMS_SCHEME_HASH Types */
+typedef TPMS_SCHEME_HASH_t TPMS_KEY_SCHEME_ECDH_t;
+typedef TPMS_SCHEME_HASH_t TPMS_KEY_SCHEME_ECMQV_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SIG_SCHEME_RSASSA_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SIG_SCHEME_RSAPSS_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SIG_SCHEME_ECDSA_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SIG_SCHEME_ECDAA_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SIG_SCHEME_SM2_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SIG_SCHEME_ECSCHNORR_t;
+typedef TPMS_SCHEME_HASH_t TPMS_ENC_SCHEME_RSAES_t;
+typedef TPMS_SCHEME_HASH_t TPMS_ENC_SCHEME_OAEP_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SCHEME_KDF2_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SCHEME_MGF1_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SCHEME_KDF1_SP800_56A_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SCHEME_KDF2_t;
+typedef TPMS_SCHEME_HASH_t TPMS_SCHEME_KDF1_SP800_108_t;
+
+/* TPMS_SCHEME_HMAC Type */
+typedef TPMS_SCHEME_HASH_t TPMS_SCHEME_HMAC_t;
+
+/* TPMS_SCHEME_XOR Structure */
+struct TPMS_SCHEME_XOR
+{
+ TPMI_ALG_HASH_t hashAlg;
+ TPMI_ALG_KDF_t kdf;
+};
+typedef struct TPMS_SCHEME_XOR TPMS_SCHEME_XOR_t;
+
+/* TPMU_SCHEME_KEYEDHASH Union */
+union TPMU_SCHEME_KEYEDHASH
+{
+ TPMS_SCHEME_HMAC_t hmac;
+ TPMS_SCHEME_XOR_t exclusiveOr;
+};
+typedef union TPMU_SCHEME_KEYEDHASH TPMU_SCHEME_KEYEDHASH_t;
+
+/* TPMT_KEYEDHASH_SCHEME Structure */
+struct TPMT_KEYEDHASH_SCHEME
+{
+ TPMI_ALG_KEYEDHASH_SCHEME_t scheme;
+ TPMU_SCHEME_KEYEDHASH_t details;
+};
+typedef struct TPMT_KEYEDHASH_SCHEME TPMT_KEYEDHASH_SCHEME_t;
+
+/* TPMS_KEYEDHASH_PARMS Structure */
+struct TPMS_KEYEDHASH_PARMS
+{
+ TPMT_KEYEDHASH_SCHEME_t scheme;
+};
+typedef struct TPMS_KEYEDHASH_PARMS TPMS_KEYEDHASH_PARMS_t;
+
+/* TPMU_SYM_KEY_BITS Union */
+union TPMU_SYM_KEY_BITS
+{
+ TPM_KEY_BITS_t aes;
+ TPM_KEY_BITS_t exclusiveOr;
+ TPM_KEY_BITS_t sm4;
+ TPM_KEY_BITS_t camellia;
+};
+typedef union TPMU_SYM_KEY_BITS TPMU_SYM_KEY_BITS_t;
+
+/* TPMU_SYM_MODE Union */
+union TPMU_SYM_MODE
+{
+ TPMI_ALG_SYM_MODE_t aes;
+ TPMI_ALG_SYM_MODE_t sm4;
+ TPMI_ALG_SYM_MODE_t camellia;
+ TPMI_ALG_SYM_MODE_t sym;
+};
+typedef union TPMU_SYM_MODE TPMU_SYM_MODE_t;
+
+/* TPMT_SYM_DEF_OBJECT Structure */
+struct TPMT_SYM_DEF_OBJECT
+{
+ TPMI_ALG_SYM_OBJECT_t algorithm;
+ TPMU_SYM_KEY_BITS_t keyBits;
+ TPMU_SYM_MODE_t mode;
+};
+typedef struct TPMT_SYM_DEF_OBJECT TPMT_SYM_DEF_OBJECT_t;
+
+/* TPMS_SYMCIPHER_PARMS Structure */
+struct TPMS_SYMCIPHER_PARMS
+{
+ TPMT_SYM_DEF_OBJECT_t sym;
+};
+typedef struct TPMS_SYMCIPHER_PARMS TPMS_SYMCIPHER_PARMS_t;
+
+/* TPMU_ASYM_SCHEME Union */
+union TPMU_ASYM_SCHEME
+{
+ TPMS_KEY_SCHEME_ECDH_t ecdh;
+ TPMS_KEY_SCHEME_ECMQV_t ecmqv;
+ TPMS_SIG_SCHEME_RSASSA_t rsassa;
+ TPMS_SIG_SCHEME_RSAPSS_t rsapss;
+ TPMS_SIG_SCHEME_ECDSA_t ecdsa;
+ TPMS_SIG_SCHEME_ECDAA_t ecdaa;
+ TPMS_SIG_SCHEME_SM2_t sm2;
+ TPMS_SIG_SCHEME_ECSCHNORR_t ecschnorr;
+ TPMS_ENC_SCHEME_RSAES_t rsaes;
+ TPMS_ENC_SCHEME_OAEP_t oaep;
+ TPMS_SCHEME_HASH_t anySig;
+ unsigned char padding[4];
+};
+typedef union TPMU_ASYM_SCHEME TPMU_ASYM_SCHEME_t;
+
+/* TPMT_RSA_SCHEME Structure */
+struct TPMT_RSA_SCHEME
+{
+ TPMI_ALG_RSA_SCHEME_t scheme;
+ TPMU_ASYM_SCHEME_t details;
+};
+typedef struct TPMT_RSA_SCHEME TPMT_RSA_SCHEME_t;
+
+/* TPMS_RSA_PARMS Structure */
+struct TPMS_RSA_PARMS
+{
+ TPMT_SYM_DEF_OBJECT_t symmetric;
+ TPMT_RSA_SCHEME_t scheme;
+ TPM_KEY_BITS_t keyBits;
+ grub_uint32_t exponent;
+};
+typedef struct TPMS_RSA_PARMS TPMS_RSA_PARMS_t;
+
+/* TPMT_ECC_SCHEME Structure */
+struct TPMT_ECC_SCHEME
+{
+ TPMI_ALG_ECC_SCHEME_t scheme;
+ TPMU_ASYM_SCHEME_t details;
+};
+typedef struct TPMT_ECC_SCHEME TPMT_ECC_SCHEME_t;
+
+/* TPMU_KDF_SCHEME Union */
+union TPMU_KDF_SCHEME
+{
+ TPMS_SCHEME_MGF1_t mgf1;
+ TPMS_SCHEME_KDF1_SP800_56A_t kdf1_sp800_56a;
+ TPMS_SCHEME_KDF2_t kdf2;
+ TPMS_SCHEME_KDF1_SP800_108_t kdf1_sp800_108;
+};
+typedef union TPMU_KDF_SCHEME TPMU_KDF_SCHEME_t;
+
+/* TPMT_KDF_SCHEME Structure */
+struct TPMT_KDF_SCHEME
+{
+ TPMI_ALG_KDF_t scheme;
+ TPMU_KDF_SCHEME_t details;
+};
+typedef struct TPMT_KDF_SCHEME TPMT_KDF_SCHEME_t;
+
+/* TPMS_ECC_PARMS Structure */
+struct TPMS_ECC_PARMS
+{
+ TPMT_SYM_DEF_OBJECT_t symmetric;
+ TPMT_ECC_SCHEME_t scheme;
+ TPMI_ECC_CURVE_t curveID;
+ TPMT_KDF_SCHEME_t kdf;
+};
+typedef struct TPMS_ECC_PARMS TPMS_ECC_PARMS_t;
+
+/* TPMT_ASYM_SCHEME Structure */
+struct TPMT_ASYM_SCHEME
+{
+ TPMI_ALG_ASYM_SCHEME_t scheme;
+ TPMU_ASYM_SCHEME_t details;
+};
+typedef struct TPMT_ASYM_SCHEME TPMT_ASYM_SCHEME_t;
+
+/* TPMS_ASYM_PARMS Structure */
+struct TPMS_ASYM_PARMS
+{
+ TPMT_SYM_DEF_OBJECT_t symmetric;
+ TPMT_ASYM_SCHEME_t scheme;
+};
+typedef struct TPMS_ASYM_PARMS TPMS_ASYM_PARMS_t;
+
+/* TPMU_PUBLIC_PARMS Union */
+union TPMU_PUBLIC_PARMS
+{
+ TPMS_KEYEDHASH_PARMS_t keyedHashDetail;
+ TPMS_SYMCIPHER_PARMS_t symDetail;
+ TPMS_RSA_PARMS_t rsaDetail;
+ TPMS_ECC_PARMS_t eccDetail;
+ TPMS_ASYM_PARMS_t asymDetail;
+};
+typedef union TPMU_PUBLIC_PARMS TPMU_PUBLIC_PARMS_t;
+
+/* TPMT_PUBLIC_PARMS Structure */
+struct TPMT_PUBLIC_PARMS {
+ TPMI_ALG_PUBLIC_t type;
+ TPMU_PUBLIC_PARMS_t parameters;
+};
+typedef struct TPMT_PUBLIC_PARMS TPMT_PUBLIC_PARMS_t;
+
+/* TPM2B_PUBLIC_KEY_RSA Structure */
+struct TPM2B_PUBLIC_KEY_RSA
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_MAX_RSA_KEY_BYTES];
+};
+typedef struct TPM2B_PUBLIC_KEY_RSA TPM2B_PUBLIC_KEY_RSA_t;
+
+/* TPM2B_ECC_PARAMETER Structure */
+struct TPM2B_ECC_PARAMETER
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_MAX_ECC_KEY_BYTES];
+};
+typedef struct TPM2B_ECC_PARAMETER TPM2B_ECC_PARAMETER_t;
+
+/* TPMS_ECC_POINT Structure */
+struct TPMS_ECC_POINT
+{
+ TPM2B_ECC_PARAMETER_t x;
+ TPM2B_ECC_PARAMETER_t y;
+};
+typedef struct TPMS_ECC_POINT TPMS_ECC_POINT_t;
+
+/* TPMU_ENCRYPTED_SECRET Union */
+union TPMU_ENCRYPTED_SECRET
+{
+ grub_uint8_t ecc[sizeof(TPMS_ECC_POINT_t)];
+ grub_uint8_t rsa[TPM_MAX_RSA_KEY_BYTES];
+ grub_uint8_t symmetric[sizeof(TPM2B_DIGEST_t)];
+ grub_uint8_t keyedHash[sizeof(TPM2B_DIGEST_t)];
+};
+typedef union TPMU_ENCRYPTED_SECRET TPMU_ENCRYPTED_SECRET_t;
+
+/* TPM2B_ENCRYPTED_SECRET Structure */
+struct TPM2B_ENCRYPTED_SECRET
+{
+ grub_uint16_t size;
+ grub_uint8_t secret[sizeof(TPMU_ENCRYPTED_SECRET_t)];
+};
+typedef struct TPM2B_ENCRYPTED_SECRET TPM2B_ENCRYPTED_SECRET_t;
+
+/* TPMU_PUBLIC_ID Union */
+union TPMU_PUBLIC_ID
+{
+ TPM2B_DIGEST_t keyedHash;
+ TPM2B_DIGEST_t sym;
+ TPM2B_PUBLIC_KEY_RSA_t rsa;
+ TPMS_ECC_POINT_t ecc;
+};
+typedef union TPMU_PUBLIC_ID TPMU_PUBLIC_ID_t;
+
+/* TPMT_PUBLIC Structure */
+struct TPMT_PUBLIC
+{
+ TPMI_ALG_PUBLIC_t type;
+ TPMI_ALG_HASH_t nameAlg;
+ TPMA_OBJECT_t objectAttributes;
+ TPM2B_DIGEST_t authPolicy;
+ TPMU_PUBLIC_PARMS_t parameters;
+ TPMU_PUBLIC_ID_t unique;
+};
+typedef struct TPMT_PUBLIC TPMT_PUBLIC_t;
+
+/* TPM2B_PUBLIC Structure */
+struct TPM2B_PUBLIC
+{
+ grub_uint16_t size;
+ TPMT_PUBLIC_t publicArea;
+};
+typedef struct TPM2B_PUBLIC TPM2B_PUBLIC_t;
+
+/* TPMT_HA Structure */
+struct TPMT_HA
+{
+ TPMI_ALG_HASH_t hashAlg;
+ TPMU_HA_t digest;
+};
+typedef struct TPMT_HA TPMT_HA_t;
+
+/* TPM2B_DATA Structure */
+struct TPM2B_DATA
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[sizeof(TPMT_HA_t)];
+};
+typedef struct TPM2B_DATA TPM2B_DATA_t;
+
+/* TPMA_LOCALITY Structure */
+struct TPMA_LOCALITY
+{
+ grub_uint8_t TPM_LOC_ZERO:1;
+ grub_uint8_t TPM_LOC_ONE:1;
+ grub_uint8_t TPM_LOC_TWO:1;
+ grub_uint8_t TPM_LOC_THREE:1;
+ grub_uint8_t TPM_LOC_FOUR:1;
+ grub_uint8_t Extended:3;
+};
+typedef struct TPMA_LOCALITY TPMA_LOCALITY_t;
+
+/* TPMU_NAME Union */
+union TPMU_NAME
+{
+ TPMT_HA_t digest;
+ TPM_HANDLE_t handle;
+};
+typedef union TPMU_NAME TPMU_NAME_t;
+
+/* TPM2B_NAME Structure */
+struct TPM2B_NAME
+{
+ grub_uint16_t size;
+ grub_uint8_t name[sizeof(TPMU_NAME_t)];
+};
+typedef struct TPM2B_NAME TPM2B_NAME_t;
+
+/* TPMS_CREATION_DATA Structure */
+struct TPMS_CREATION_DATA
+{
+ TPML_PCR_SELECTION_t pcrSelect;
+ TPM2B_DIGEST_t pcrDigest;
+ TPMA_LOCALITY_t locality;
+ TPM_ALG_ID_t parentNameAlg;
+ TPM2B_NAME_t parentName;
+ TPM2B_NAME_t parentQualifiedName;
+ TPM2B_DATA_t outsideInfo;
+};
+typedef struct TPMS_CREATION_DATA TPMS_CREATION_DATA_t;
+
+/* TPM2B_CREATION_DATA Structure */
+struct TPM2B_CREATION_DATA
+{
+ grub_uint16_t size;
+ TPMS_CREATION_DATA_t creationData;
+};
+typedef struct TPM2B_CREATION_DATA TPM2B_CREATION_DATA_t;
+
+/* TPMT_SYM_DEF Structure */
+struct TPMT_SYM_DEF
+{
+ TPMI_ALG_SYM_t algorithm;
+ TPMU_SYM_KEY_BITS_t keyBits;
+ TPMU_SYM_MODE_t mode;
+};
+typedef struct TPMT_SYM_DEF TPMT_SYM_DEF_t;
+
+/* TPM2B_MAX_BUFFER Structure */
+struct TPM2B_MAX_BUFFER
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_MAX_DIGEST_BUFFER];
+};
+typedef struct TPM2B_MAX_BUFFER TPM2B_MAX_BUFFER_t;
+
+/* TPMT_TK_HASHCHECK Structure */
+struct TPMT_TK_HASHCHECK
+{
+ TPM_ST_t tag;
+ TPMI_RH_HIERARCHY_t hierarchy;
+ TPM2B_DIGEST_t digest;
+};
+typedef struct TPMT_TK_HASHCHECK TPMT_TK_HASHCHECK_t;
+
+/* TPM2B_SYM_KEY Structure */
+struct TPM2B_SYM_KEY
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_MAX_SYM_KEY_BYTES];
+};
+typedef struct TPM2B_SYM_KEY TPM2B_SYM_KEY_t;
+
+/* TPM2B_PRIVATE_KEY_RSA Structure */
+struct TPM2B_PRIVATE_KEY_RSA
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_MAX_RSA_KEY_BYTES/2];
+};
+typedef struct TPM2B_PRIVATE_KEY_RSA TPM2B_PRIVATE_KEY_RSA_t;
+
+/* TPM2B_PRIVATE_VENDOR_SPECIFIC Structure */
+struct TPM2B_PRIVATE_VENDOR_SPECIFIC
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_PRIVATE_VENDOR_SPECIFIC_BYTES];
+};
+typedef struct TPM2B_PRIVATE_VENDOR_SPECIFIC TPM2B_PRIVATE_VENDOR_SPECIFIC_t;
+
+/* TPM2B_PRIVATE_VENDOR_SPECIFIC Union */
+union TPMU_SENSITIVE_COMPOSITE
+{
+ TPM2B_PRIVATE_KEY_RSA_t rsa;
+ TPM2B_ECC_PARAMETER_t ecc;
+ TPM2B_SENSITIVE_DATA_t bits;
+ TPM2B_SYM_KEY_t sym;
+ TPM2B_PRIVATE_VENDOR_SPECIFIC_t any;
+};
+typedef union TPMU_SENSITIVE_COMPOSITE TPMU_SENSITIVE_COMPOSITE_t;
+
+/* TPMT_SENSITIVE Structure */
+struct TPMT_SENSITIVE
+{
+ TPMI_ALG_PUBLIC_t sensitiveType;
+ TPM2B_AUTH_t authValue;
+ TPM2B_DIGEST_t seedValue;
+ TPMU_SENSITIVE_COMPOSITE_t sensitive;
+};
+typedef struct TPMT_SENSITIVE TPMT_SENSITIVE_t;
+
+/* TPM2B_SENSITIVE Structure */
+struct TPM2B_SENSITIVE
+{
+ grub_uint16_t size;
+ TPMT_SENSITIVE_t sensitiveArea;
+};
+typedef struct TPM2B_SENSITIVE TPM2B_SENSITIVE_t;
+
+/*
+ * _PRIVATE Structure
+ *
+ * Although '_PRIVATE' is the name defined in the TPM2 SPEC, it is too generic,
+ * so here we add the '__TPM2B' prefix to make the struct specific for 'TPM2B_PRIVATE'.
+ */
+struct __TPM2B_PRIVATE
+{
+ TPM2B_DIGEST_t integrityOuter;
+ TPM2B_DIGEST_t integrityInner;
+ TPM2B_SENSITIVE_t sensitive;
+};
+typedef struct __TPM2B_PRIVATE __TPM2B_PRIVATE_t;
+
+/* TPM2B_PRIVATE Structure */
+struct TPM2B_PRIVATE
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[sizeof(__TPM2B_PRIVATE_t)];
+};
+typedef struct TPM2B_PRIVATE TPM2B_PRIVATE_t;
+
+/* TPML_DIGEST_VALUES Structure */
+struct TPML_DIGEST_VALUES
+{
+ grub_uint16_t count;
+ TPMT_HA_t digests[TPM_NUM_PCR_BANKS];
+};
+typedef struct TPML_DIGEST_VALUES TPML_DIGEST_VALUES_t;
+
+/* TPM2B_MAX_NV_BUFFER Structure */
+struct TPM2B_MAX_NV_BUFFER
+{
+ grub_uint16_t size;
+ grub_uint8_t buffer[TPM_MAX_NV_BUFFER_SIZE];
+};
+typedef struct TPM2B_MAX_NV_BUFFER TPM2B_MAX_NV_BUFFER_t;
+
+/* TPMS_NV_PUBLIC Structure */
+struct TPMS_NV_PUBLIC
+{
+ TPMI_RH_NV_INDEX_t nvIndex;
+ TPMI_ALG_HASH_t nameAlg;
+ TPMA_NV_t attributes;
+ TPM2B_DIGEST_t authPolicy;
+ grub_uint16_t dataSize;
+};
+typedef struct TPMS_NV_PUBLIC TPMS_NV_PUBLIC_t;
+
+/* TPM2B_NV_PUBLIC Structure */
+struct TPM2B_NV_PUBLIC
+{
+ grub_uint16_t size;
+ TPMS_NV_PUBLIC_t nvPublic;
+};
+typedef struct TPM2B_NV_PUBLIC TPM2B_NV_PUBLIC_t;
+
+/* TPMT_TK_CREATION Structure */
+struct TPMT_TK_CREATION
+{
+ TPM_ST_t tag;
+ TPMI_RH_HIERARCHY_t hierarchy;
+ TPM2B_DIGEST_t digest;
+};
+typedef struct TPMT_TK_CREATION TPMT_TK_CREATION_t;
+
+/* TPMS_EMPTY Structure */
+struct TPMS_EMPTY {
+ grub_uint8_t empty[1]; /* a structure with no member */
+};
+typedef struct TPMS_EMPTY TPMS_EMPTY_t;
+
+/* TPMS_SIGNATURE_RSA Structure */
+struct TPMS_SIGNATURE_RSA {
+ TPMI_ALG_HASH_t hash;
+ TPM2B_PUBLIC_KEY_RSA_t sig;
+};
+typedef struct TPMS_SIGNATURE_RSA TPMS_SIGNATURE_RSA_t;
+
+/* Definition of Types for RSA Signature */
+typedef TPMS_SIGNATURE_RSA_t TPMS_SIGNATURE_RSASSA_t;
+typedef TPMS_SIGNATURE_RSA_t TPMS_SIGNATURE_RSAPSS_t;
+
+/* TPMS_SIGNATURE_ECC Structure */
+struct TPMS_SIGNATURE_ECC {
+ TPMI_ALG_HASH_t hash;
+ TPM2B_ECC_PARAMETER_t signatureR;
+ TPM2B_ECC_PARAMETER_t signatureS;
+};
+typedef struct TPMS_SIGNATURE_ECC TPMS_SIGNATURE_ECC_t;
+
+/* Definition of Types for ECC TPMS_SIGNATURE_ECC */
+typedef TPMS_SIGNATURE_ECC_t TPMS_SIGNATURE_ECDSA_t;
+typedef TPMS_SIGNATURE_ECC_t TPMS_SIGNATURE_ECDAA_t;
+typedef TPMS_SIGNATURE_ECC_t TPMS_SIGNATURE_SM2_t;
+typedef TPMS_SIGNATURE_ECC_t TPMS_SIGNATURE_ECSCHNORR_t;
+
+/* TPMU_SIGNATURE Structure */
+union TPMU_SIGNATURE {
+ TPMS_SIGNATURE_RSASSA_t rsassa;
+ TPMS_SIGNATURE_RSAPSS_t rsapss;
+ TPMS_SIGNATURE_ECDSA_t ecdsa;
+ TPMS_SIGNATURE_ECDAA_t ecdaa;
+ TPMS_SIGNATURE_SM2_t sm2;
+ TPMS_SIGNATURE_ECSCHNORR_t ecschnorr;
+ TPMT_HA_t hmac;
+ TPMS_SCHEME_HASH_t any;
+ TPMS_EMPTY_t null;
+};
+typedef union TPMU_SIGNATURE TPMU_SIGNATURE_t;
+
+/* TPMT_SIGNATURE Structure */
+struct TPMT_SIGNATURE {
+ TPMI_ALG_SIG_SCHEME_t sigAlg;
+ TPMU_SIGNATURE_t signature;
+};
+typedef struct TPMT_SIGNATURE TPMT_SIGNATURE_t;
+
+static inline TPMI_ALG_HASH_t
+TPMT_SIGNATURE_get_hash_alg (TPMT_SIGNATURE_t *sig)
+{
+ switch (sig->sigAlg)
+ {
+ case TPM_ALG_RSASSA:
+ return sig->signature.rsassa.hash;
+ case TPM_ALG_RSAPSS:
+ return sig->signature.rsapss.hash;
+ case TPM_ALG_ECDSA:
+ return sig->signature.ecdsa.hash;
+ case TPM_ALG_ECDAA:
+ return sig->signature.ecdaa.hash;
+ case TPM_ALG_SM2:
+ return sig->signature.sm2.hash;
+ case TPM_ALG_ECSCHNORR:
+ return sig->signature.ecschnorr.hash;
+ case TPM_ALG_HMAC:
+ return sig->signature.hmac.hashAlg;
+ default:
+ break;
+ }
+
+ return TPM_ALG_NULL;
+}
+
+/* TPMT_TK_VERIFIED Structure */
+struct TPMT_TK_VERIFIED {
+ TPM_ST_t tag;
+ TPMI_RH_HIERARCHY_t hierarchy;
+ TPM2B_DIGEST_t digest;
+};
+typedef struct TPMT_TK_VERIFIED TPMT_TK_VERIFIED_t;
+
+#endif /* ! GRUB_TPM2_INTERNAL_STRUCTS_HEADER */
diff --git a/grub-core/lib/tss2/tss2_types.h b/grub-core/lib/tss2/tss2_types.h
new file mode 100644
index 000000000..a8f040b29
--- /dev/null
+++ b/grub-core/lib/tss2/tss2_types.h
@@ -0,0 +1,404 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_INTERNAL_TYPES_HEADER
+#define GRUB_TPM2_INTERNAL_TYPES_HEADER 1
+
+#include <grub/types.h>
+
+/* TPM2_RC Constants */
+typedef grub_uint32_t TPM_RC_t;
+
+#define TPM_RC_1 ((TPM_RC_t) 0x100)
+#define TPM_RC_2 ((TPM_RC_t) 0x200)
+#define TPM_RC_3 ((TPM_RC_t) 0x300)
+#define TPM_RC_4 ((TPM_RC_t) 0x400)
+#define TPM_RC_5 ((TPM_RC_t) 0x500)
+#define TPM_RC_6 ((TPM_RC_t) 0x600)
+#define TPM_RC_7 ((TPM_RC_t) 0x700)
+#define TPM_RC_8 ((TPM_RC_t) 0x800)
+#define TPM_RC_9 ((TPM_RC_t) 0x900)
+#define TPM_RC_A ((TPM_RC_t) 0xA00)
+#define TPM_RC_ASYMMETRIC ((TPM_RC_t) 0x081)
+#define TPM_RC_ATTRIBUTES ((TPM_RC_t) 0x082)
+#define TPM_RC_AUTH_CONTEXT ((TPM_RC_t) 0x145)
+#define TPM_RC_AUTH_FAIL ((TPM_RC_t) 0x08E)
+#define TPM_RC_AUTH_MISSING ((TPM_RC_t) 0x125)
+#define TPM_RC_AUTHSIZE ((TPM_RC_t) 0x144)
+#define TPM_RC_AUTH_TYPE ((TPM_RC_t) 0x124)
+#define TPM_RC_AUTH_UNAVAILABLE ((TPM_RC_t) 0x12F)
+#define TPM_RC_B ((TPM_RC_t) 0xB00)
+#define TPM_RC_BAD_AUTH ((TPM_RC_t) 0x0A2)
+#define TPM_RC_BAD_CONTEXT ((TPM_RC_t) 0x150)
+#define TPM_RC_BAD_TAG ((TPM_RC_t) 0x01E)
+#define TPM_RC_BINDING ((TPM_RC_t) 0x0A5)
+#define TPM_RC_C ((TPM_RC_t) 0xC00)
+#define TPM_RC_CANCELED ((TPM_RC_t) 0x909)
+#define TPM_RC_COMMAND_CODE ((TPM_RC_t) 0x143)
+#define TPM_RC_COMMAND_SIZE ((TPM_RC_t) 0x142)
+#define TPM_RC_CONTEXT_GAP ((TPM_RC_t) 0x901)
+#define TPM_RC_CPHASH ((TPM_RC_t) 0x151)
+#define TPM_RC_CURVE ((TPM_RC_t) 0x0A6)
+#define TPM_RC_D ((TPM_RC_t) 0xD00)
+#define TPM_RC_DISABLED ((TPM_RC_t) 0x120)
+#define TPM_RC_E ((TPM_RC_t) 0xE00)
+#define TPM_RC_ECC_POINT ((TPM_RC_t) 0x0A7)
+#define TPM_RC_EXCLUSIVE ((TPM_RC_t) 0x121)
+#define TPM_RC_EXPIRED ((TPM_RC_t) 0x0A3)
+#define TPM_RC_F ((TPM_RC_t) 0xF00)
+#define TPM_RC_FAILURE ((TPM_RC_t) 0x101)
+#define TPM_RC_H ((TPM_RC_t) 0x000)
+#define TPM_RC_HANDLE ((TPM_RC_t) 0x08B)
+#define TPM_RC_HASH ((TPM_RC_t) 0x083)
+#define TPM_RC_HIERARCHY ((TPM_RC_t) 0x085)
+#define TPM_RC_HMAC ((TPM_RC_t) 0x119)
+#define TPM_RC_INITIALIZE ((TPM_RC_t) 0x100)
+#define TPM_RC_INSUFFICIENT ((TPM_RC_t) 0x09A)
+#define TPM_RC_INTEGRITY ((TPM_RC_t) 0x09F)
+#define TPM_RC_KDF ((TPM_RC_t) 0x08C)
+#define TPM_RC_KEY ((TPM_RC_t) 0x09C)
+#define TPM_RC_KEY_SIZE ((TPM_RC_t) 0x087)
+#define TPM_RC_LOCALITY ((TPM_RC_t) 0x907)
+#define TPM_RC_LOCKOUT ((TPM_RC_t) 0x921)
+#define TPM_RC_MEMORY ((TPM_RC_t) 0x904)
+#define TPM_RC_MGF ((TPM_RC_t) 0x088)
+#define TPM_RC_MODE ((TPM_RC_t) 0x089)
+#define TPM_RC_NEEDS_TEST ((TPM_RC_t) 0x153)
+#define TPM_RC_N_MASK ((TPM_RC_t) 0xF00)
+#define TPM_RC_NONCE ((TPM_RC_t) 0x08F)
+#define TPM_RC_NO_RESULT ((TPM_RC_t) 0x154)
+#define TPM_RC_NOT_USED ((TPM_RC_t) 0x97F)
+#define TPM_RC_NV_AUTHORIZATION ((TPM_RC_t) 0x149)
+#define TPM_RC_NV_DEFINED ((TPM_RC_t) 0x14C)
+#define TPM_RC_NV_LOCKED ((TPM_RC_t) 0x148)
+#define TPM_RC_NV_RANGE ((TPM_RC_t) 0x146)
+#define TPM_RC_NV_RATE ((TPM_RC_t) 0x920)
+#define TPM_RC_NV_SIZE ((TPM_RC_t) 0x147)
+#define TPM_RC_NV_SPACE ((TPM_RC_t) 0x14B)
+#define TPM_RC_NV_UNAVAILABLE ((TPM_RC_t) 0x923)
+#define TPM_RC_NV_UNINITIALIZED ((TPM_RC_t) 0x14A)
+#define TPM_RC_OBJECT_HANDLES ((TPM_RC_t) 0x906)
+#define TPM_RC_OBJECT_MEMORY ((TPM_RC_t) 0x902)
+#define TPM_RC_P ((TPM_RC_t) 0x040)
+#define TPM_RC_PARENT ((TPM_RC_t) 0x152)
+#define TPM_RC_PCR ((TPM_RC_t) 0x127)
+#define TPM_RC_PCR_CHANGED ((TPM_RC_t) 0x128)
+#define TPM_RC_POLICY ((TPM_RC_t) 0x126)
+#define TPM_RC_POLICY_CC ((TPM_RC_t) 0x0A4)
+#define TPM_RC_POLICY_FAIL ((TPM_RC_t) 0x09D)
+#define TPM_RC_PP ((TPM_RC_t) 0x090)
+#define TPM_RC_PRIVATE ((TPM_RC_t) 0x10B)
+#define TPM_RC_RANGE ((TPM_RC_t) 0x08D)
+#define TPM_RC_REBOOT ((TPM_RC_t) 0x130)
+#define TPM_RC_REFERENCE_H0 ((TPM_RC_t) 0x910)
+#define TPM_RC_REFERENCE_H1 ((TPM_RC_t) 0x911)
+#define TPM_RC_REFERENCE_H2 ((TPM_RC_t) 0x912)
+#define TPM_RC_REFERENCE_H3 ((TPM_RC_t) 0x913)
+#define TPM_RC_REFERENCE_H4 ((TPM_RC_t) 0x914)
+#define TPM_RC_REFERENCE_H5 ((TPM_RC_t) 0x915)
+#define TPM_RC_REFERENCE_H6 ((TPM_RC_t) 0x916)
+#define TPM_RC_REFERENCE_S0 ((TPM_RC_t) 0x918)
+#define TPM_RC_REFERENCE_S1 ((TPM_RC_t) 0x919)
+#define TPM_RC_REFERENCE_S2 ((TPM_RC_t) 0x91A)
+#define TPM_RC_REFERENCE_S3 ((TPM_RC_t) 0x91B)
+#define TPM_RC_REFERENCE_S4 ((TPM_RC_t) 0x91C)
+#define TPM_RC_REFERENCE_S5 ((TPM_RC_t) 0x91D)
+#define TPM_RC_REFERENCE_S6 ((TPM_RC_t) 0x91E)
+#define TPM_RC_RESERVED_BITS ((TPM_RC_t) 0x0A1)
+#define TPM_RC_RETRY ((TPM_RC_t) 0x922)
+#define TPM_RC_S ((TPM_RC_t) 0x800)
+#define TPM_RC_SCHEME ((TPM_RC_t) 0x092)
+#define TPM_RC_SELECTOR ((TPM_RC_t) 0x098)
+#define TPM_RC_SENSITIVE ((TPM_RC_t) 0x155)
+#define TPM_RC_SEQUENCE ((TPM_RC_t) 0x103)
+#define TPM_RC_SESSION_HANDLES ((TPM_RC_t) 0x905)
+#define TPM_RC_SESSION_MEMORY ((TPM_RC_t) 0x903)
+#define TPM_RC_SIGNATURE ((TPM_RC_t) 0x09B)
+#define TPM_RC_SIZE ((TPM_RC_t) 0x095)
+#define TPM_RC_SUCCESS ((TPM_RC_t) 0x000)
+#define TPM_RC_SYMMETRIC ((TPM_RC_t) 0x096)
+#define TPM_RC_TAG ((TPM_RC_t) 0x097)
+#define TPM_RC_TESTING ((TPM_RC_t) 0x90A)
+#define TPM_RC_TICKET ((TPM_RC_t) 0x0A0)
+#define TPM_RC_TOO_MANY_CONTEXTS ((TPM_RC_t) 0x12E)
+#define TPM_RC_TYPE ((TPM_RC_t) 0x08A)
+#define TPM_RC_UNBALANCED ((TPM_RC_t) 0x131)
+#define TPM_RC_UPGRADE ((TPM_RC_t) 0x12D)
+#define TPM_RC_VALUE ((TPM_RC_t) 0x084)
+#define TPM_RC_YIELDED ((TPM_RC_t) 0x908)
+
+/* TPMA_NV_t Constants */
+typedef grub_uint32_t TPMA_NV_t;
+
+#define TPMA_NV_PPWRITE ((TPMA_NV_t) 0x00000001)
+#define TPMA_NV_OWNERWRITE ((TPMA_NV_t) 0x00000002)
+#define TPMA_NV_AUTHWRITE ((TPMA_NV_t) 0x00000004)
+#define TPMA_NV_POLICYWRITE ((TPMA_NV_t) 0x00000008)
+#define TPMA_NV_TPM2_NT_MASK ((TPMA_NV_t) 0x000000F0)
+#define TPMA_NV_TPM2_NT_SHIFT (4)
+#define TPMA_NV_RESERVED1_MASK ((TPMA_NV_t) 0x00000300)
+#define TPMA_NV_POLICY_DELETE ((TPMA_NV_t) 0x00000400)
+#define TPMA_NV_WRITELOCKED ((TPMA_NV_t) 0x00000800)
+#define TPMA_NV_WRITEALL ((TPMA_NV_t) 0x00001000)
+#define TPMA_NV_WRITEDEFINE ((TPMA_NV_t) 0x00002000)
+#define TPMA_NV_WRITE_STCLEAR ((TPMA_NV_t) 0x00004000)
+#define TPMA_NV_GLOBALLOCK ((TPMA_NV_t) 0x00008000)
+#define TPMA_NV_PPREAD ((TPMA_NV_t) 0x00010000)
+#define TPMA_NV_OWNERREAD ((TPMA_NV_t) 0x00020000)
+#define TPMA_NV_AUTHREAD ((TPMA_NV_t) 0x00040000)
+#define TPMA_NV_POLICYREAD ((TPMA_NV_t) 0x00080000)
+#define TPMA_NV_RESERVED2_MASK ((TPMA_NV_t) 0x01F00000)
+#define TPMA_NV_NO_DA ((TPMA_NV_t) 0x02000000)
+#define TPMA_NV_ORDERLY ((TPMA_NV_t) 0x04000000)
+#define TPMA_NV_CLEAR_STCLEAR ((TPMA_NV_t) 0x08000000)
+#define TPMA_NV_READLOCKED ((TPMA_NV_t) 0x10000000)
+#define TPMA_NV_WRITTEN ((TPMA_NV_t) 0x20000000)
+#define TPMA_NV_PLATFORMCREATE ((TPMA_NV_t) 0x40000000)
+#define TPMA_NV_READ_STCLEAR ((TPMA_NV_t) 0x80000000)
+
+/* TPM_ALG_ID_t Constants */
+typedef grub_uint16_t TPM_ALG_ID_t;
+
+#define TPM_ALG_ERROR ((TPM_ALG_ID_t) 0x0000)
+#define TPM_ALG_AES ((TPM_ALG_ID_t) 0x0006)
+#define TPM_ALG_CAMELLIA ((TPM_ALG_ID_t) 0x0026)
+#define TPM_ALG_CBC ((TPM_ALG_ID_t) 0x0042)
+#define TPM_ALG_CFB ((TPM_ALG_ID_t) 0x0043)
+#define TPM_ALG_ECB ((TPM_ALG_ID_t) 0x0044)
+#define TPM_ALG_ECC ((TPM_ALG_ID_t) 0x0023)
+#define TPM_ALG_ECDAA ((TPM_ALG_ID_t) 0x001A)
+#define TPM_ALG_ECDSA ((TPM_ALG_ID_t) 0x0018)
+#define TPM_ALG_ECSCHNORR ((TPM_ALG_ID_t) 0x001C)
+#define TPM_ALG_HMAC ((TPM_ALG_ID_t) 0x0005)
+#define TPM_ALG_KDF1_SP800_108 ((TPM_ALG_ID_t) 0x0022)
+#define TPM_ALG_KDF1_SP800_56A ((TPM_ALG_ID_t) 0x0020)
+#define TPM_ALG_KDF2 ((TPM_ALG_ID_t) 0x0021)
+#define TPM_ALG_KEYEDHASH ((TPM_ALG_ID_t) 0x0008)
+#define TPM_ALG_MGF1 ((TPM_ALG_ID_t) 0x0007)
+#define TPM_ALG_NULL ((TPM_ALG_ID_t) 0x0010)
+#define TPM_ALG_RSA ((TPM_ALG_ID_t) 0x0001)
+#define TPM_ALG_RSASSA ((TPM_ALG_ID_t) 0x0014)
+#define TPM_ALG_RSAPSS ((TPM_ALG_ID_t) 0x0016)
+#define TPM_ALG_SHA1 ((TPM_ALG_ID_t) 0x0004)
+#define TPM_ALG_SHA256 ((TPM_ALG_ID_t) 0x000B)
+#define TPM_ALG_SHA384 ((TPM_ALG_ID_t) 0x000C)
+#define TPM_ALG_SHA512 ((TPM_ALG_ID_t) 0x000D)
+#define TPM_ALG_SM2 ((TPM_ALG_ID_t) 0x001B)
+#define TPM_ALG_SM3_256 ((TPM_ALG_ID_t) 0x0012)
+#define TPM_ALG_SM4 ((TPM_ALG_ID_t) 0x0013)
+#define TPM_ALG_SYMCIPHER ((TPM_ALG_ID_t) 0x0025)
+#define TPM_ALG_XOR ((TPM_ALG_ID_t) 0x000A)
+
+/* TPM_CAP_t Constants */
+typedef grub_uint32_t TPM_CAP_t;
+
+#define TPM_CAP_FIRST ((TPM_CAP_t) 0x00000000)
+#define TPM_CAP_ALGS ((TPM_CAP_t) 0x00000000)
+#define TPM_CAP_HANDLES ((TPM_CAP_t) 0x00000001)
+#define TPM_CAP_COMMANDS ((TPM_CAP_t) 0x00000002)
+#define TPM_CAP_PP_COMMANDS ((TPM_CAP_t) 0x00000003)
+#define TPM_CAP_AUDIT_COMMANDS ((TPM_CAP_t) 0x00000004)
+#define TPM_CAP_PCRS ((TPM_CAP_t) 0x00000005)
+#define TPM_CAP_TPM_PROPERTIES ((TPM_CAP_t) 0x00000006)
+#define TPM_CAP_PCR_PROPERTIES ((TPM_CAP_t) 0x00000007)
+#define TPM_CAP_ECC_CURVES ((TPM_CAP_t) 0x00000008)
+#define TPM_CAP_LAST ((TPM_CAP_t) 0x00000008)
+#define TPM_CAP_VENDOR_PROPERTY ((TPM_CAP_t) 0x00000100)
+
+/* TPM_PT_t Constants */
+typedef grub_uint32_t TPM_PT_t;
+
+#define TPM_PT_NONE ((TPM_PT_t) 0x00000000)
+#define PT_GROUP ((TPM_PT_t) 0x00000100)
+#define PT_FIXED ((TPM_PT_t) (PT_GROUP * 1))
+#define TPM_PT_FAMILY_INDICATOR ((TPM_PT_t) (PT_FIXED + 0))
+#define TPM_PT_LEVEL ((TPM_PT_t) (PT_FIXED + 1))
+#define TPM_PT_REVISION ((TPM_PT_t) (PT_FIXED + 2))
+#define TPM_PT_DAY_OF_YEAR ((TPM_PT_t) (PT_FIXED + 3))
+#define TPM_PT_YEAR ((TPM_PT_t) (PT_FIXED + 4))
+#define TPM_PT_PCR_COUNT ((TPM_PT_t) (PT_FIXED + 18))
+
+/* TPM_SE_t Constants */
+typedef grub_uint8_t TPM_SE_t;
+
+#define TPM_SE_HMAC ((TPM_SE_t) 0x00)
+#define TPM_SE_POLICY ((TPM_SE_t) 0x01)
+#define TPM_SE_TRIAL ((TPM_SE_t) 0x03)
+
+/* TPMI_YES_NO_t Constants */
+typedef grub_uint8_t TPMI_YES_NO_t;
+
+#define TPM_NO ((TPMI_YES_NO_t)0)
+#define TPM_YES ((TPMI_YES_NO_t)1)
+
+/* TPM_ST_t Constants */
+typedef grub_uint16_t TPM_ST_t;
+typedef TPM_ST_t TPMI_ST_COMMAND_TAG_t;
+
+#define TPM_ST_NO_SESSIONS ((TPMI_ST_COMMAND_TAG_t) 0x8001)
+#define TPM_ST_SESSIONS ((TPMI_ST_COMMAND_TAG_t) 0x8002)
+
+/* TPM_HANDLE_t Types */
+typedef grub_uint32_t TPM_HANDLE_t;
+
+typedef TPM_HANDLE_t TPMI_RH_HIERARCHY_t;
+typedef TPM_HANDLE_t TPMI_RH_LOCKOUT_t;
+typedef TPM_HANDLE_t TPMI_SH_AUTH_SESSION_t;
+typedef TPM_HANDLE_t TPMI_DH_CONTEXT_t;
+typedef TPM_HANDLE_t TPMI_DH_OBJECT_t;
+typedef TPM_HANDLE_t TPMI_DH_ENTITY_t;
+typedef TPM_HANDLE_t TPMI_SH_POLICY_t;
+typedef TPM_HANDLE_t TPMI_DH_PCR_t;
+typedef TPM_HANDLE_t TPMI_RH_NV_AUTH_t;
+typedef TPM_HANDLE_t TPMI_RH_NV_INDEX_t;
+
+/* TPM_HT_t Constants */
+typedef grub_uint8_t TPM_HT_t;
+#define TPM_HT_PERMANENT ((TPM_HT_t) 0x40)
+#define TPM_HT_PERSISTENT ((TPM_HT_t) 0x81)
+
+/* TPM_RH_t Constants */
+typedef TPM_HANDLE_t TPM_RH_t;
+
+#define TPM_RH_FIRST ((TPM_RH_t) 0x40000000)
+#define TPM_RH_SRK ((TPM_RH_t) 0x40000000)
+#define TPM_RH_OWNER ((TPM_RH_t) 0x40000001)
+#define TPM_RH_REVOKE ((TPM_RH_t) 0x40000002)
+#define TPM_RH_TRANSPORT ((TPM_RH_t) 0x40000003)
+#define TPM_RH_OPERATOR ((TPM_RH_t) 0x40000004)
+#define TPM_RH_ADMIN ((TPM_RH_t) 0x40000005)
+#define TPM_RH_EK ((TPM_RH_t) 0x40000006)
+#define TPM_RH_NULL ((TPM_RH_t) 0x40000007)
+#define TPM_RH_UNASSIGNED ((TPM_RH_t) 0x40000008)
+#define TPM_RS_PW ((TPM_RH_t) 0x40000009)
+#define TPM_RH_LOCKOUT ((TPM_RH_t) 0x4000000A)
+#define TPM_RH_ENDORSEMENT ((TPM_RH_t) 0x4000000B)
+#define TPM_RH_PLATFORM ((TPM_RH_t) 0x4000000C)
+#define TPM_RH_PLATFORM_NV ((TPM_RH_t) 0x4000000D)
+#define TPM_RH_AUTH_00 ((TPM_RH_t) 0x40000010)
+#define TPM_RH_AUTH_FF ((TPM_RH_t) 0x4000010F)
+#define TPM_RH_LAST ((TPM_RH_t) 0x4000010F)
+
+/* TPM_HC_t Constants */
+typedef TPM_HANDLE_t TPM_HC_t;
+#define TPM_HR_HANDLE_MASK ((TPM_HC_t) 0x00FFFFFF)
+#define TPM_HR_RANGE_MASK ((TPM_HC_t) 0xFF000000)
+#define TPM_HR_SHIFT ((TPM_HC_t) 24)
+#define TPM_HR_PERSISTENT ((TPM_HC_t) (TPM_HT_PERSISTENT << TPM_HR_SHIFT))
+#define TPM_HR_PERMANENT ((TPM_HC_t) (TPM_HT_PERMANENT << TPM_HR_SHIFT))
+#define TPM_PERSISTENT_FIRST ((TPM_HC_t) (TPM_HR_PERSISTENT + 0))
+#define TPM_PERSISTENT_LAST ((TPM_HC_t) (TPM_PERSISTENT_FIRST + 0x00FFFFFF))
+#define TPM_PERMANENT_FIRST ((TPM_HC_t) TPM_RH_FIRST)
+#define TPM_PERMANENT_LAST ((TPM_HC_t) TPM_RH_LAST)
+
+/* TPM Handle Type Checks */
+#define TPM_HT_IS_PERMANENT(HANDLE) (((HANDLE) >> TPM_HR_SHIFT) == TPM_HT_PERMANENT)
+#define TPM_HT_IS_PERSISTENT(HANDLE) (((HANDLE) >> TPM_HR_SHIFT) == TPM_HT_PERSISTENT)
+
+/* TPM_ECC_CURVE_t Constants */
+typedef grub_uint16_t TPM_ECC_CURVE_t;
+
+#define TPM_ECC_NONE ((TPM_ECC_CURVE_t) 0x0000)
+#define TPM_ECC_NIST_P192 ((TPM_ECC_CURVE_t) 0x0001)
+#define TPM_ECC_NIST_P224 ((TPM_ECC_CURVE_t) 0x0002)
+#define TPM_ECC_NIST_P256 ((TPM_ECC_CURVE_t) 0x0003)
+#define TPM_ECC_NIST_P384 ((TPM_ECC_CURVE_t) 0x0004)
+#define TPM_ECC_NIST_P521 ((TPM_ECC_CURVE_t) 0x0005)
+#define TPM_ECC_BN_P256 ((TPM_ECC_CURVE_t) 0x0010)
+#define TPM_ECC_BN_P638 ((TPM_ECC_CURVE_t) 0x0011)
+#define TPM_ECC_SM2_P256 ((TPM_ECC_CURVE_t) 0x0020)
+
+/* TPM_CC_t Constants */
+typedef grub_uint32_t TPM_CC_t;
+
+#define TPM_CC_EvictControl ((TPM_CC_t) 0x00000120)
+#define TPM_CC_CreatePrimary ((TPM_CC_t) 0x00000131)
+#define TPM_CC_Create ((TPM_CC_t) 0x00000153)
+#define TPM_CC_FlushContext ((TPM_CC_t) 0x00000165)
+#define TPM_CC_ReadPublic ((TPM_CC_t) 0x00000173)
+#define TPM_CC_StartAuthSession ((TPM_CC_t) 0x00000176)
+#define TPM_CC_PolicyPCR ((TPM_CC_t) 0x0000017f)
+#define TPM_CC_NV_Read ((TPM_CC_t) 0x0000014e)
+#define TPM_CC_NV_ReadPublic ((TPM_CC_t) 0x00000169)
+#define TPM_CC_GetCapability ((TPM_CC_t) 0x0000017a)
+#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)
+#define TPM_CC_Unseal ((TPM_CC_t) 0x0000015e)
+#define TPM_CC_PolicyGetDigest ((TPM_CC_t) 0x00000189)
+#define TPM_CC_Hash ((TPM_CC_t) 0x0000017d)
+#define TPM_CC_VerifySignature ((TPM_CC_t) 0x00000177)
+#define TPM_CC_PolicyAuthorize ((TPM_CC_t) 0x0000016a)
+#define TPM_CC_TestParms ((TPM_CC_t) 0x0000018a)
+
+/* Hash algorithm sizes */
+#define TPM_SHA1_DIGEST_SIZE 20
+#define TPM_SHA256_DIGEST_SIZE 32
+#define TPM_SM3_256_DIGEST_SIZE 32
+#define TPM_SHA384_DIGEST_SIZE 48
+#define TPM_SHA512_DIGEST_SIZE 64
+
+/* Encryption algorithm sizes */
+#define TPM_MAX_SYM_BLOCK_SIZE 16
+#define TPM_MAX_SYM_DATA 256
+#define TPM_MAX_ECC_KEY_BYTES 128
+#define TPM_MAX_SYM_KEY_BYTES 32
+#define TPM_MAX_RSA_KEY_BYTES 512
+
+/* Buffer Size Constants */
+#define TPM_MAX_PCRS 32
+#define TPM_NUM_PCR_BANKS 16
+#define TPM_PCR_SELECT_MAX ((TPM_MAX_PCRS + 7) / 8)
+#define TPM_MAX_DIGEST_BUFFER 1024
+#define TPM_MAX_TPM_PROPERTIES 8
+#define TPM_MAX_NV_BUFFER_SIZE 2048
+#define TPM_PRIVATE_VENDOR_SPECIFIC_BYTES 1280
+
+/* TPM_GENERATED_t Constants */
+typedef grub_uint32_t TPM_GENERATED_t;
+
+#define TPM_GENERATED_VALUE ((TPM_GENERATED_t) 0xff544347)
+
+/* TPM_ALG_ID_t Types */
+typedef TPM_ALG_ID_t TPMI_ALG_PUBLIC_t;
+typedef TPM_ALG_ID_t TPMI_ALG_HASH_t;
+typedef TPM_ALG_ID_t TPMI_ALG_KEYEDHASH_SCHEME_t;
+typedef TPM_ALG_ID_t TPMI_ALG_KDF_t;
+typedef TPM_ALG_ID_t TPMI_ALG_SYM_OBJECT_t;
+typedef TPM_ALG_ID_t TPMI_ALG_SYM_MODE_t;
+typedef TPM_ALG_ID_t TPMI_ALG_RSA_DECRYPT_t;
+typedef TPM_ALG_ID_t TPMI_ALG_ECC_SCHEME_t;
+typedef TPM_ALG_ID_t TPMI_ALG_ASYM_SCHEME_t;
+typedef TPM_ALG_ID_t TPMI_ALG_RSA_SCHEME_t;
+typedef TPM_ALG_ID_t TPMI_ALG_SYM_t;
+typedef TPM_ALG_ID_t TPMI_ALG_SIG_SCHEME_t;
+
+/* TPM_KEY_BITS_t Type */
+typedef grub_uint16_t TPM_KEY_BITS_t;
+
+/* TPMI_ECC_CURVE_t Types */
+typedef TPM_ECC_CURVE_t TPMI_ECC_CURVE_t;
+
+/* TPMI_RH_PROVISION_t Type */
+typedef TPM_HANDLE_t TPMI_RH_PROVISION_t;
+
+/* TPMI_RH_PROVISION_t Type */
+typedef TPM_HANDLE_t TPMI_DH_PERSISTENT_t;
+
+#endif /* ! GRUB_TPM2_INTERNAL_TYPES_HEADER */
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (19 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 20/33] tss2: Add TPM2 types and Marshal/Unmarshal functions Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-18 3:14 ` Stefan Berger
2024-09-06 9:11 ` [PATCH v19 22/33] key_protector: Add TPM2 Key Protector Gary Lin via Grub-devel
` (13 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to
compose and submit TPM commands and parse reponses.
A limited number of TPM commands may be accessed via the EFI TCG2
protocol. This protocol exposes functionality that is primarily geared
toward TPM usage within the context of Secure Boot. For all other TPM
commands, however, such as sealing and unsealing, this protocol does not
provide any help, with the exception of passthrough command submission.
The SubmitCommand method allows a caller to send raw commands to the
system's TPM and to receive the corresponding response. These
command/response pairs are formatted using the TPM wire protocol. To
construct commands in this way, and to parse the TPM's response, it is
necessary to, first, possess knowledge of the various TPM structures, and,
second, of the TPM wire protocol itself.
As such, this patch includes implementations of various grub_tpm2_* functions
(inventoried below), and logic to write and read command and response
buffers, respectively, using the TPM wire protocol.
Functions:
* grub_tpm2_create()
* grub_tpm2_createprimary()
* grub_tpm2_evictcontrol()
* grub_tpm2_flushcontext()
* grub_tpm2_load()
* grub_tpm2_pcr_read()
* grub_tpm2_policygetdigest()
* grub_tpm2_policypcr()
* grub_tpm2_readpublic()
* grub_tpm2_startauthsession()
* grub_tpm2_unseal()
* grub_tpm2_loadexternal()
* grub_tpm2_hash()
* grub_tpm2_verifysignature()
* grub_tpm2_policyauthorize()
* grub_tpm2_testparms()
Cc: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.core.def | 11 +
grub-core/lib/efi/tcg2.c | 143 +++++
grub-core/lib/tss2/tcg2.h | 35 ++
grub-core/lib/tss2/tpm2_cmd.c | 1043 +++++++++++++++++++++++++++++++++
grub-core/lib/tss2/tpm2_cmd.h | 157 +++++
grub-core/lib/tss2/tss2.c | 21 +
6 files changed, 1410 insertions(+)
create mode 100644 grub-core/lib/efi/tcg2.c
create mode 100644 grub-core/lib/tss2/tcg2.h
create mode 100644 grub-core/lib/tss2/tpm2_cmd.c
create mode 100644 grub-core/lib/tss2/tpm2_cmd.h
create mode 100644 grub-core/lib/tss2/tss2.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 37f131ae2..45b705a34 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2567,6 +2567,17 @@ module = {
enable = efi;
};
+module = {
+ name = tss2;
+ common = lib/tss2/buffer.c;
+ common = lib/tss2/tss2_mu.c;
+ common = lib/tss2/tpm2_cmd.c;
+ common = lib/tss2/tss2.c;
+ efi = lib/efi/tcg2.c;
+ enable = efi;
+ cppflags = '-I$(srcdir)/lib/tss2';
+};
+
module = {
name = tr;
common = commands/tr.c;
diff --git a/grub-core/lib/efi/tcg2.c b/grub-core/lib/efi/tcg2.c
new file mode 100644
index 000000000..841bf50bb
--- /dev/null
+++ b/grub-core/lib/efi/tcg2.c
@@ -0,0 +1,143 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/tpm.h>
+#include <grub/mm.h>
+
+#include <tcg2.h>
+
+static grub_err_t
+tcg2_get_caps (grub_efi_tpm2_protocol_t *protocol, int *tpm2, grub_size_t *max_output_size)
+{
+ grub_efi_status_t status;
+ static bool has_caps = 0;
+ static EFI_TCG2_BOOT_SERVICE_CAPABILITY caps =
+ {
+ .Size = (grub_uint8_t) sizeof (caps)
+ };
+
+ if (has_caps)
+ goto exit;
+
+ status = protocol->get_capability (protocol, &caps);
+ if (status != GRUB_EFI_SUCCESS || !caps.TPMPresentFlag)
+ return GRUB_ERR_FILE_NOT_FOUND;
+
+ has_caps = 1;
+
+ exit:
+ if (tpm2 != NULL)
+ *tpm2 = caps.TPMPresentFlag;
+ if (max_output_size != NULL)
+ *max_output_size = caps.MaxResponseSize;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tcg2_get_protocol (grub_efi_tpm2_protocol_t **protocol)
+{
+ static grub_guid_t tpm2_guid = EFI_TPM2_GUID;
+ static grub_efi_tpm2_protocol_t *tpm2_protocol = NULL;
+ int tpm2;
+ grub_efi_handle_t *handles;
+ grub_efi_uintn_t num_handles;
+ grub_efi_handle_t tpm2_handle;
+ grub_err_t err = GRUB_ERR_FILE_NOT_FOUND;
+
+ if (tpm2_protocol != NULL)
+ {
+ *protocol = tpm2_protocol;
+ return GRUB_ERR_NONE;
+ }
+
+ handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &tpm2_guid, NULL,
+ &num_handles);
+ if (handles == NULL || num_handles == 0)
+ return err;
+
+ tpm2_handle = handles[0];
+
+ tpm2_protocol = grub_efi_open_protocol (tpm2_handle, &tpm2_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (tpm2_protocol == NULL)
+ goto exit;
+
+ err = tcg2_get_caps (tpm2_protocol, &tpm2, NULL);
+ if (err != GRUB_ERR_NONE || tpm2 == 0)
+ goto exit;
+
+ *protocol = tpm2_protocol;
+ err = GRUB_ERR_NONE;
+
+ exit:
+ grub_free (handles);
+ return err;
+}
+
+grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size)
+{
+ grub_err_t err;
+ grub_size_t max;
+ grub_efi_tpm2_protocol_t *protocol;
+
+ if (size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ err = tcg2_get_protocol (&protocol);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = tcg2_get_caps (protocol, NULL, &max);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ *size = max;
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tcg2_submit_command (grub_size_t input_size,
+ grub_uint8_t *input,
+ grub_size_t output_size,
+ grub_uint8_t *output)
+{
+ grub_err_t err;
+ grub_efi_status_t status;
+ grub_efi_tpm2_protocol_t *protocol;
+
+ if (input_size == 0 || input == NULL ||
+ output_size == 0 || output == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ err = tcg2_get_protocol (&protocol);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ status = protocol->submit_command (protocol, input_size, input,
+ output_size, output);
+ if (status != GRUB_EFI_SUCCESS)
+ return GRUB_ERR_INVALID_COMMAND;
+
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/lib/tss2/tcg2.h b/grub-core/lib/tss2/tcg2.h
new file mode 100644
index 000000000..3d26373dd
--- /dev/null
+++ b/grub-core/lib/tss2/tcg2.h
@@ -0,0 +1,35 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_TCG2_HEADER
+#define GRUB_TPM2_TCG2_HEADER 1
+
+#include <grub/err.h>
+#include <grub/types.h>
+
+extern grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size);
+
+extern grub_err_t
+grub_tcg2_submit_command (grub_size_t input_size,
+ grub_uint8_t *input,
+ grub_size_t output_size,
+ grub_uint8_t *output);
+
+#endif /* ! GRUB_TPM2_TCG2_HEADER */
diff --git a/grub-core/lib/tss2/tpm2_cmd.c b/grub-core/lib/tss2/tpm2_cmd.c
new file mode 100644
index 000000000..8a86139ed
--- /dev/null
+++ b/grub-core/lib/tss2/tpm2_cmd.c
@@ -0,0 +1,1043 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/types.h>
+
+#include <tss2_buffer.h>
+#include <tss2_mu.h>
+#include <tss2_structs.h>
+#include <tcg2.h>
+#include <tpm2_cmd.h>
+
+static TPM_RC_t
+tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG_t tag,
+ const TPM_CC_t commandCode,
+ TPM_RC_t *responseCode,
+ const struct grub_tpm2_buffer *in,
+ struct grub_tpm2_buffer *out)
+{
+ grub_err_t err;
+ struct grub_tpm2_buffer buf;
+ TPMI_ST_COMMAND_TAG_t tag_out;
+ grub_uint32_t command_size;
+ grub_size_t max_output_size;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&buf);
+ grub_tpm2_buffer_pack_u16 (&buf, tag);
+ grub_tpm2_buffer_pack_u32 (&buf, 0);
+ grub_tpm2_buffer_pack_u32 (&buf, commandCode);
+ grub_tpm2_buffer_pack (&buf, in->data, in->size);
+
+ if (buf.error != 0)
+ return TPM_RC_FAILURE;
+
+ command_size = grub_swap_bytes32 (buf.size);
+ grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size,
+ sizeof (command_size));
+
+ /* Stay within output block limits */
+ err = grub_tcg2_get_max_output_size (&max_output_size);
+ if (err != GRUB_ERR_NONE || max_output_size > out->cap)
+ max_output_size = out->cap - 1;
+
+ /* Submit */
+ err = grub_tcg2_submit_command (buf.size, buf.data, max_output_size, out->data);
+ if (err != GRUB_ERR_NONE)
+ return TPM_RC_FAILURE;
+
+ /* Unmarshal */
+ out->size = sizeof (grub_uint16_t) + sizeof (grub_uint32_t) + sizeof (grub_uint32_t);
+ grub_tpm2_buffer_unpack_u16 (out, &tag_out);
+ grub_tpm2_buffer_unpack_u32 (out, &command_size);
+ grub_tpm2_buffer_unpack_u32 (out, responseCode);
+ out->size = command_size;
+ if (out->error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+static TPM_RC_t
+tpm2_submit_command (const TPMI_ST_COMMAND_TAG_t tag,
+ const TPM_CC_t commandCode,
+ TPM_RC_t *responseCode,
+ const struct grub_tpm2_buffer *in,
+ struct grub_tpm2_buffer *out)
+{
+ TPM_RC_t err;
+ int retry_cnt = 0;
+
+ /* Catch TPM_RC_RETRY and send the command again */
+ do {
+ err = tpm2_submit_command_real (tag, commandCode, responseCode, in, out);
+ if (*responseCode != TPM_RC_RETRY)
+ break;
+
+ retry_cnt++;
+ } while (retry_cnt < 3);
+
+ return err;
+}
+
+TPM_RC_t
+grub_tpm2_createprimary (const TPMI_RH_HIERARCHY_t primaryHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
+ const TPM2B_PUBLIC_t *inPublic,
+ const TPM2B_DATA_t *outsideInfo,
+ const TPML_PCR_SELECTION_t *creationPCR,
+ TPM_HANDLE_t *objectHandle,
+ TPM2B_PUBLIC_t *outPublic,
+ TPM2B_CREATION_DATA_t *creationData,
+ TPM2B_DIGEST_t *creationHash,
+ TPMT_TK_CREATION_t *creationTicket,
+ TPM2B_NAME_t *name,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM_HANDLE_t objectHandleTmp;
+ TPM2B_PUBLIC_t outPublicTmp;
+ TPM2B_CREATION_DATA_t creationDataTmp;
+ TPM2B_DIGEST_t creationHashTmp;
+ TPMT_TK_CREATION_t creationTicketTmp;
+ TPM2B_NAME_t nameTmp;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ if (inSensitive == NULL || inPublic == NULL || outsideInfo == NULL ||
+ creationPCR == NULL)
+ return TPM_RC_VALUE;
+
+ if (objectHandle == NULL)
+ objectHandle = &objectHandleTmp;
+ if (outPublic == NULL)
+ outPublic = &outPublicTmp;
+ if (creationData == NULL)
+ creationData = &creationDataTmp;
+ if (creationHash == NULL)
+ creationHash = &creationHashTmp;
+ if (creationTicket == NULL)
+ creationTicket = &creationTicketTmp;
+ if (name == NULL)
+ name = &nameTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (outPublic, 0, sizeof (*outPublic));
+ grub_memset (creationData, 0, sizeof (*creationData));
+ grub_memset (creationHash, 0, sizeof (*creationHash));
+ grub_memset (creationTicket, 0, sizeof (*creationTicket));
+ grub_memset (name, 0, sizeof (*name));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, primaryHandle);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_Tss2_MU_TPM2B_SENSITIVE_CREATE_Marshal (&in, inSensitive);
+ grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&in, inPublic);
+ grub_Tss2_MU_TPM2B_Marshal (&in, outsideInfo->size, outsideInfo->buffer);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (&in, creationPCR);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ grub_tpm2_buffer_unpack_u32 (&out, objectHandle);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (&out, outPublic);
+ grub_Tss2_MU_TPM2B_CREATION_DATA_Unmarshal (&out, creationData);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (&out, creationHash);
+ grub_Tss2_MU_TPMT_TK_CREATION_Unmarshal (&out, creationTicket);
+ grub_Tss2_MU_TPM2B_NAME_Unmarshal (&out, name);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_startauthsession (const TPMI_DH_OBJECT_t tpmKey,
+ const TPMI_DH_ENTITY_t bind,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_NONCE_t *nonceCaller,
+ const TPM2B_ENCRYPTED_SECRET_t *encryptedSalt,
+ const TPM_SE_t sessionType,
+ const TPMT_SYM_DEF_t *symmetric,
+ const TPMI_ALG_HASH_t authHash,
+ TPMI_SH_AUTH_SESSION_t *sessionHandle,
+ TPM2B_NONCE_t *nonceTpm,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_SH_AUTH_SESSION_t sessionHandleTmp;
+ TPM2B_NONCE_t nonceTpmTmp;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (nonceCaller == NULL || symmetric == NULL)
+ return TPM_RC_VALUE;
+
+ if (tpmKey == TPM_RH_NULL &&
+ (encryptedSalt && encryptedSalt->size != 0))
+ return TPM_RC_VALUE;
+
+ if (sessionHandle == NULL)
+ sessionHandle = &sessionHandleTmp;
+ if (nonceTpm == NULL)
+ nonceTpm = &nonceTpmTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (sessionHandle, 0, sizeof (*sessionHandle));
+ grub_memset (nonceTpm, 0, sizeof (*nonceTpm));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, tpmKey);
+ grub_tpm2_buffer_pack_u32 (&in, bind);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_Tss2_MU_TPM2B_Marshal (&in, nonceCaller->size, nonceCaller->buffer);
+ if (encryptedSalt != NULL)
+ grub_Tss2_MU_TPM2B_Marshal (&in, encryptedSalt->size, encryptedSalt->secret);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_tpm2_buffer_pack_u8 (&in, sessionType);
+ grub_Tss2_MU_TPMT_SYM_DEF_Marshal (&in, symmetric);
+ grub_tpm2_buffer_pack_u16 (&in, authHash);
+ if (in.error != 0)
+ 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)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ grub_tpm2_buffer_unpack_u32 (&out, sessionHandle);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_Tss2_MU_TPM2B_NONCE_Unmarshal (&out, nonceTpm);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_policypcr (const TPMI_SH_POLICY_t policySessions,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_DIGEST_t *pcrDigest,
+ const TPML_PCR_SELECTION_t *pcrs,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (pcrs == NULL)
+ return TPM_RC_VALUE;
+
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, policySessions);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (pcrDigest != NULL)
+ grub_Tss2_MU_TPM2B_Marshal (&in, pcrDigest->size, pcrDigest->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (&in, pcrs);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal*/
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_readpublic (const TPMI_DH_OBJECT_t objectHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_PUBLIC_t *outPublic)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, objectHandle);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (&out, outPublic);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_load (const TPMI_DH_OBJECT_t parent_handle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_PRIVATE_t *inPrivate,
+ const TPM2B_PUBLIC_t *inPublic,
+ TPM_HANDLE_t *objectHandle,
+ TPM2B_NAME_t *name,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM_HANDLE_t objectHandleTmp;
+ TPM2B_NAME_t nameTmp;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (inPrivate == NULL || inPublic == NULL)
+ return TPM_RC_VALUE;
+
+ if (objectHandle == NULL)
+ objectHandle = &objectHandleTmp;
+ if (name == NULL)
+ name = &nameTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (objectHandle, 0, sizeof (*objectHandle));
+ grub_memset (name, 0, sizeof (*name));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, parent_handle);
+ if (authCommand)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_Tss2_MU_TPM2B_Marshal (&in, inPrivate->size, inPrivate->buffer);
+ grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&in, inPublic);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ grub_tpm2_buffer_unpack_u32 (&out, objectHandle);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_Tss2_MU_TPM2B_NAME_Unmarshal (&out, name);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_loadexternal (const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_SENSITIVE_t *inPrivate,
+ const TPM2B_PUBLIC_t *inPublic,
+ const TPMI_RH_HIERARCHY_t hierarchy,
+ TPM_HANDLE_t *objectHandle,
+ TPM2B_NAME_t *name,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM_HANDLE_t objectHandleTmp;
+ TPM2B_NAME_t nameTmp;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (inPublic == NULL)
+ return TPM_RC_VALUE;
+
+ if (objectHandle == NULL)
+ objectHandle = &objectHandleTmp;
+ if (name == NULL)
+ name = &nameTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (objectHandle, 0, sizeof (*objectHandle));
+ grub_memset (name, 0, sizeof (*name));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (inPrivate)
+ grub_Tss2_MU_TPM2B_SENSITIVE_Marshal (&in, inPrivate);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&in, inPublic);
+ grub_tpm2_buffer_pack_u32 (&in, hierarchy);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ grub_tpm2_buffer_unpack_u32 (&out, objectHandle);
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_Tss2_MU_TPM2B_NAME_Unmarshal (&out, name);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_unseal (const TPMI_DH_OBJECT_t itemHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_SENSITIVE_DATA_t *outData,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM2B_SENSITIVE_DATA_t outDataTmp;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (outData == NULL)
+ outData = &outDataTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (outData, 0, sizeof (*outData));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, itemHandle);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_Tss2_MU_TPM2B_SENSITIVE_DATA_Unmarshal (&out, outData);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM_RC_t responseCode;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, handle);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (out.error != 0)
+ 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,
+ grub_uint32_t *pcrUpdateCounter,
+ TPML_PCR_SELECTION_t *pcrSelectionOut,
+ TPML_DIGEST_t *pcrValues,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ grub_uint32_t pcrUpdateCounterTmp;
+ TPML_PCR_SELECTION_t pcrSelectionOutTmp;
+ TPML_DIGEST_t pcrValuesTmp;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ if (pcrSelectionIn == NULL)
+ return TPM_RC_VALUE;
+
+ if (pcrUpdateCounter == NULL)
+ pcrUpdateCounter = &pcrUpdateCounterTmp;
+ if (pcrSelectionOut == NULL)
+ pcrSelectionOut = &pcrSelectionOutTmp;
+ if (pcrValues == NULL)
+ pcrValues = &pcrValuesTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (&in, pcrSelectionIn);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_tpm2_buffer_unpack_u32 (&out, pcrUpdateCounter);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Unmarshal (&out, pcrSelectionOut);
+ grub_Tss2_MU_TPML_DIGEST_Unmarshal (&out, pcrValues);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_policygetdigest (const TPMI_SH_POLICY_t policySession,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_DIGEST_t *policyDigest,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPM2B_DIGEST_t policyDigestTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t parameterSize;
+
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+ if (policyDigest == NULL)
+ policyDigest = &policyDigestTmp;
+
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+ grub_memset (policyDigest, 0, sizeof (*policyDigest));
+
+ /* Submit */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, policySession);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (&out, policyDigest);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_create (const TPMI_DH_OBJECT_t parentHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
+ const TPM2B_PUBLIC_t *inPublic,
+ const TPM2B_DATA_t *outsideInfo,
+ const TPML_PCR_SELECTION_t *creationPCR,
+ TPM2B_PRIVATE_t *outPrivate,
+ TPM2B_PUBLIC_t *outPublic,
+ TPM2B_CREATION_DATA_t *creationData,
+ TPM2B_DIGEST_t *creationHash,
+ TPMT_TK_CREATION_t *creationTicket,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPM2B_PUBLIC_t outPublicTmp;
+ TPM2B_PRIVATE_t outPrivateTmp;
+ TPM2B_CREATION_DATA_t creationDataTmp;
+ TPM2B_DIGEST_t creationHashTmp;
+ TPMT_TK_CREATION_t creationTicketTmp;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS:TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ TPM_RC_t rc;
+ grub_uint32_t parameterSize;
+
+ if (inSensitive == NULL || inPublic == NULL || outsideInfo == NULL ||
+ creationPCR == NULL)
+ return TPM_RC_VALUE;
+
+ if (outPrivate == NULL)
+ outPrivate = &outPrivateTmp;
+ if (outPublic == NULL)
+ outPublic = &outPublicTmp;
+ if (creationData == NULL)
+ creationData = &creationDataTmp;
+ if (creationHash == NULL)
+ creationHash = &creationHashTmp;
+ if (creationTicket == NULL)
+ creationTicket = &creationTicketTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (outPrivate, 0, sizeof (*outPrivate));
+ grub_memset (outPublic, 0, sizeof (*outPublic));
+ grub_memset (creationData, 0, sizeof (*creationData));
+ grub_memset (creationHash, 0, sizeof (*creationHash));
+ grub_memset (creationTicket, 0, sizeof (*creationTicket));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, parentHandle);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_Tss2_MU_TPM2B_SENSITIVE_CREATE_Marshal (&in, inSensitive);
+ grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&in, inPublic);
+ grub_Tss2_MU_TPM2B_Marshal (&in, outsideInfo->size, outsideInfo->buffer);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (&in, creationPCR);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_Tss2_MU_TPM2B_PRIVATE_Unmarshal (&out, outPrivate);
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (&out, outPublic);
+ grub_Tss2_MU_TPM2B_CREATION_DATA_Unmarshal (&out, creationData);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (&out, creationHash);
+ grub_Tss2_MU_TPMT_TK_CREATION_Unmarshal (&out, creationTicket);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_evictcontrol (const TPMI_RH_PROVISION_t auth,
+ const TPMI_DH_OBJECT_t objectHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPMI_DH_PERSISTENT_t persistentHandle,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ TPM_RC_t rc;
+ grub_uint32_t parameterSize;
+
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, auth);
+ grub_tpm2_buffer_pack_u32 (&in, objectHandle);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_tpm2_buffer_pack_u32 (&in, persistentHandle);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ {
+ grub_tpm2_buffer_unpack_u32 (&out, ¶meterSize);
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal(&out, authResponse);
+ }
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_hash (const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_MAX_BUFFER_t *data,
+ const TPMI_ALG_HASH_t hashAlg,
+ const TPMI_RH_HIERARCHY_t hierarchy,
+ TPM2B_DIGEST_t *outHash,
+ TPMT_TK_HASHCHECK_t *validation,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPM2B_DIGEST_t outHashTmp;
+ TPMT_TK_HASHCHECK_t validationTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (hashAlg == TPM_ALG_NULL)
+ return TPM_RC_VALUE;
+
+ if (outHash == NULL)
+ outHash = &outHashTmp;
+ if (validation == NULL)
+ validation = &validationTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (outHash, 0, sizeof (*outHash));
+ grub_memset (validation, 0, sizeof (*validation));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (data != NULL)
+ grub_Tss2_MU_TPM2B_Marshal (&in, data->size, data->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_tpm2_buffer_pack_u16 (&in, hashAlg);
+ grub_tpm2_buffer_pack_u32 (&in, hierarchy);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (&out, outHash);
+ grub_Tss2_MU_TPMT_TK_HASHCHECK_Unmarshal (&out, validation);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_verifysignature (const TPMI_DH_OBJECT_t keyHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_DIGEST_t *digest,
+ const TPMT_SIGNATURE_t *signature,
+ TPMT_TK_VERIFIED_t *validation,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPMT_TK_VERIFIED_t validationTmp;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (digest == NULL || signature == NULL)
+ return TPM_RC_VALUE;
+
+ if (validation == NULL)
+ validation = &validationTmp;
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (validation, 0, sizeof (*validation));
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_tpm2_buffer_pack_u32 (&in, keyHandle);
+ grub_Tss2_MU_TPM2B_Marshal (&in, digest->size, digest->buffer);
+ grub_Tss2_MU_TPMT_SIGNATURE_Marshal (&in, signature);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_Tss2_MU_TPMT_TK_VERIFIED_Unmarshal (&out, validation);
+ if (tag == TPM_ST_SESSIONS)
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_policyauthorize (const TPMI_SH_POLICY_t policySession,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_DIGEST_t *approvedPolicy,
+ const TPM2B_NONCE_t *policyRef,
+ const TPM2B_NAME_t *keySign,
+ const TPMT_TK_VERIFIED_t *checkTicket,
+ TPMS_AUTH_RESPONSE_t *authResponse)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMS_AUTH_RESPONSE_t authResponseTmp;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ if (approvedPolicy == NULL || keySign == NULL || checkTicket == NULL)
+ return TPM_RC_VALUE;
+
+ if (authResponse == NULL)
+ authResponse = &authResponseTmp;
+
+ grub_memset (authResponse, 0, sizeof (*authResponse));
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, policySession);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_Tss2_MU_TPM2B_Marshal (&in, approvedPolicy->size, approvedPolicy->buffer);
+ if (policyRef != NULL)
+ grub_Tss2_MU_TPM2B_Marshal (&in, policyRef->size, policyRef->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_Tss2_MU_TPM2B_Marshal (&in, keySign->size, keySign->name);
+ grub_Tss2_MU_TPMT_TK_VERIFIED_Marshal (&in, checkTicket);
+ if (in.error != 0)
+ 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;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ {
+ grub_tpm2_buffer_unpack_u32 (&out, ¶m_size);
+ grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (&out, authResponse);
+ }
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
+ const TPMS_AUTH_COMMAND_t *authCommand)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+
+ if (parms == NULL)
+ return TPM_RC_VALUE;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_Tss2_MU_TPMT_PUBLIC_PARMS_Marshal (&in, parms);
+ if (in.error != 0)
+ 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)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
diff --git a/grub-core/lib/tss2/tpm2_cmd.h b/grub-core/lib/tss2/tpm2_cmd.h
new file mode 100644
index 000000000..d313cba00
--- /dev/null
+++ b/grub-core/lib/tss2/tpm2_cmd.h
@@ -0,0 +1,157 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_COMMANDS_HEADER
+#define GRUB_TPM2_COMMANDS_HEADER 1
+
+#include <tss2_structs.h>
+
+extern TPM_RC_t
+grub_tpm2_createprimary (const TPMI_RH_HIERARCHY_t primaryHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
+ const TPM2B_PUBLIC_t *inPublic,
+ const TPM2B_DATA_t *outsideInfo,
+ const TPML_PCR_SELECTION_t *creationPCR,
+ TPM_HANDLE_t *objectHandle,
+ TPM2B_PUBLIC_t *outPublic,
+ TPM2B_CREATION_DATA_t *creationData,
+ TPM2B_DIGEST_t *creationHash,
+ TPMT_TK_CREATION_t *creationTicket,
+ TPM2B_NAME_t *name,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_startauthsession (const TPMI_DH_OBJECT_t tpmKey,
+ const TPMI_DH_ENTITY_t bind,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_NONCE_t *nonceCaller,
+ const TPM2B_ENCRYPTED_SECRET_t *encryptedSalt,
+ const TPM_SE_t sessionType,
+ const TPMT_SYM_DEF_t *symmetric,
+ const TPMI_ALG_HASH_t authHash,
+ TPMI_SH_AUTH_SESSION_t *sessionHandle,
+ TPM2B_NONCE_t *nonceTpm,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_policypcr (const TPMI_SH_POLICY_t policySession,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_DIGEST_t *pcrDigest,
+ const TPML_PCR_SELECTION_t *pcrs,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_readpublic (const TPMI_DH_OBJECT_t objectHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_PUBLIC_t *outPublic);
+
+extern TPM_RC_t
+grub_tpm2_load (const TPMI_DH_OBJECT_t parent_handle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_PRIVATE_t *inPrivate,
+ const TPM2B_PUBLIC_t *inPublic,
+ TPM_HANDLE_t *objectHandle,
+ TPM2B_NAME_t *name,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_loadexternal (const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_SENSITIVE_t *inPrivate,
+ const TPM2B_PUBLIC_t *inPublic,
+ const TPMI_RH_HIERARCHY_t hierarchy,
+ TPM_HANDLE_t *objectHandle,
+ TPM2B_NAME_t *name,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_unseal (const TPMI_DH_OBJECT_t item_handle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_SENSITIVE_DATA_t *outData,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_flushcontext (const TPMI_DH_CONTEXT_t handle);
+
+extern TPM_RC_t
+grub_tpm2_pcr_read (const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPML_PCR_SELECTION_t *pcrSelectionIn,
+ grub_uint32_t *pcrUpdateCounter,
+ TPML_PCR_SELECTION_t *pcrSelectionOut,
+ TPML_DIGEST_t *pcrValues,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_policygetdigest (const TPMI_SH_POLICY_t policySession,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_DIGEST_t *policyDigest,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_create (const TPMI_DH_OBJECT_t parentHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_SENSITIVE_CREATE_t *inSensitive,
+ const TPM2B_PUBLIC_t *inPublic,
+ const TPM2B_DATA_t *outsideInfo,
+ const TPML_PCR_SELECTION_t *creationPCR,
+ TPM2B_PRIVATE_t *outPrivate,
+ TPM2B_PUBLIC_t *outPublic,
+ TPM2B_CREATION_DATA_t *creationData,
+ TPM2B_DIGEST_t *creationHash,
+ TPMT_TK_CREATION_t *creationTicket,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_evictcontrol (const TPMI_RH_PROVISION_t auth,
+ const TPMI_DH_OBJECT_t objectHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPMI_DH_PERSISTENT_t persistentHandle,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_hash (const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_MAX_BUFFER_t *data,
+ const TPMI_ALG_HASH_t hashAlg,
+ const TPMI_RH_HIERARCHY_t hierarchy,
+ TPM2B_DIGEST_t *outHash,
+ TPMT_TK_HASHCHECK_t *validation,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_verifysignature (const TPMI_DH_OBJECT_t keyHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_DIGEST_t *digest,
+ const TPMT_SIGNATURE_t *signature,
+ TPMT_TK_VERIFIED_t *validation,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_policyauthorize (const TPMI_SH_POLICY_t policySession,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_DIGEST_t *approvedPolicy,
+ const TPM2B_NONCE_t *policyRef,
+ const TPM2B_NAME_t *keySign,
+ const TPMT_TK_VERIFIED_t *checkTicket,
+ TPMS_AUTH_RESPONSE_t *authResponse);
+
+extern TPM_RC_t
+grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
+ const TPMS_AUTH_COMMAND_t *authCommand);
+
+#endif /* ! GRUB_TPM2_COMMANDS_HEADER */
diff --git a/grub-core/lib/tss2/tss2.c b/grub-core/lib/tss2/tss2.c
new file mode 100644
index 000000000..48251e9b4
--- /dev/null
+++ b/grub-core/lib/tss2/tss2.c
@@ -0,0 +1,21 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 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+");
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 22/33] key_protector: Add TPM2 Key Protector
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (20 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-18 15:22 ` Stefan Berger
2024-10-16 15:44 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 23/33] cryptodisk: Support key protectors Gary Lin via Grub-devel
` (12 subsequent siblings)
34 siblings, 2 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Hernan Gatta <hegatta@linux.microsoft.com>
The TPM2 key protector is a module that enables the automatic retrieval
of a fully-encrypted disk's unlocking key from a TPM 2.0.
The theory of operation is such that the module accepts various
arguments, most of which are optional and therefore possess reasonable
defaults. One of these arguments is the keyfile/tpm2key parameter, which
is mandatory. There are two supported key formats:
1. Raw Sealed Key (--keyfile)
When sealing a key with TPM2_Create, the public portion of the sealed
key is stored in TPM2B_PUBLIC, and the private portion is in
TPM2B_PRIVATE. The raw sealed key glues the fully marshalled
TPM2B_PUBLIC and TPM2B_PRIVATE into one file.
2. TPM 2.0 Key (--tpm2key)
The following is the ASN.1 definition of TPM 2.0 Key File:
TPMPolicy ::= SEQUENCE {
CommandCode [0] EXPLICIT INTEGER
CommandPolicy [1] EXPLICIT OCTET STRING
}
TPMAuthPolicy ::= SEQUENCE {
Name [0] EXPLICIT UTF8STRING OPTIONAL
Policy [1] EXPLICIT SEQUENCE OF TPMPolicy
}
TPMKey ::= SEQUENCE {
type OBJECT IDENTIFIER
emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL
policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
secret [2] EXPLICIT OCTET STRING OPTIONAL
authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
description [4] EXPLICIT UTF8String OPTIONAL,
rsaParent [5] EXPLICIT BOOLEAN OPTIONAL,
parent INTEGER
pubkey OCTET STRING
privkey OCTET STRING
}
The TPM2 key protector only expects a "sealed" key in DER encoding,
so 'type' is always 2.23.133.10.1.5, 'emptyAuth' is 'TRUE', and
'secret' is empty. 'policy' and 'authPolicy' are the possible policy
command sequences to construst the policy digest to unseal the key.
Similar to the raw sealed key, the public portion (TPM2B_PUBLIC) of
the sealed key is stored in 'pubkey', and the private portion
(TPM2B_PRIVATE) is in 'privkey'.
For more details: https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
This sealed key file is created via the grub-protect tool. The tool
utilizes the TPM's sealing functionality to seal (i.e., encrypt) an
unlocking key using a Storage Root Key (SRK) to the values of various
Platform Configuration Registers (PCRs). These PCRs reflect the state
of the system as it boots. If the values are as expected, the system
may be considered trustworthy, at which point the TPM allows for a
caller to utilize the private component of the SRK to unseal (i.e.,
decrypt) the sealed key file. The caller, in this case, is this key
protector.
The TPM2 key protector registers two commands:
- tpm2_key_protector_init: Initializes the state of the TPM2 key
protector for later usage, clearing any
previous state, too, if any.
- tpm2_key_protector_clear: Clears any state set by tpm2_key_protector_init.
The way this is expected to be used requires the user to, either
interactively or, normally, via a boot script, initialize/configure
the key protector and then specify that it be used by the 'cryptomount'
command (modifications to this command are in a different patch).
For instance, to unseal the raw sealed key file:
tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-1.key
cryptomount -u <PART1_UUID> -P tpm2
tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-2.key --pcrs=7,11
cryptomount -u <PART2_UUID> -P tpm2
Or, to unseal the TPM 2.0 Key file:
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-1.tpm
cryptomount -u <PART1_UUID> -P tpm2
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-2.tpm --pcrs=7,11
cryptomount -u <PART2_UUID> -P tpm2
If a user does not initialize the key protector and attempts to use it
anyway, the protector returns an error.
Before unsealing the key, the TPM2 key protector follows the "TPMPolicy"
sequences to enforce the TPM policy commands to construct a valid policy
digest to unseal the key.
For the TPM 2.0 Key files, 'authPolicy' may contain multiple "TPMPolicy"
sequences, the TPM2 key protector iterates 'authPolicy' to find a valid
sequence to unseal key. If 'authPolicy' is empty or all sequences in
'authPolicy' fail, the protector tries the one from 'policy'. In case
'policy' is also empty, the protector creates a "TPMPolicy" sequence
based on the given PCR selection.
For the raw sealed key, the TPM2 key protector treats the key file as a
TPM 2.0 Key file without 'authPolicy' and 'policy', so the "TPMPolicy"
sequence is always based on the PCR selection from the command
parameters.
This commit only supports one policy command: TPM2_PolicyPCR. The
command set will be extended to support advanced features, such as
authorized policy, in the later commits.
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/Makefile.core.def | 11 +
grub-core/commands/tpm2_key_protector/args.c | 129 ++
.../commands/tpm2_key_protector/module.c | 1153 +++++++++++++++++
grub-core/commands/tpm2_key_protector/tpm2.h | 36 +
.../commands/tpm2_key_protector/tpm2_args.h | 49 +
.../commands/tpm2_key_protector/tpm2key.asn | 49 +
.../commands/tpm2_key_protector/tpm2key.c | 499 +++++++
.../commands/tpm2_key_protector/tpm2key.h | 87 ++
.../tpm2_key_protector/tpm2key_asn1_tab.c | 63 +
9 files changed, 2076 insertions(+)
create mode 100644 grub-core/commands/tpm2_key_protector/args.c
create mode 100644 grub-core/commands/tpm2_key_protector/module.c
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2.h
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2_args.h
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.asn
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.c
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.h
create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 45b705a34..97ae4e49b 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2578,6 +2578,17 @@ module = {
cppflags = '-I$(srcdir)/lib/tss2';
};
+module = {
+ name = tpm2_key_protector;
+ common = commands/tpm2_key_protector/args.c;
+ common = commands/tpm2_key_protector/module.c;
+ common = commands/tpm2_key_protector/tpm2key.c;
+ common = commands/tpm2_key_protector/tpm2key_asn1_tab.c;
+ /* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */
+ enable = efi;
+ cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub';
+};
+
module = {
name = tr;
common = commands/tr.c;
diff --git a/grub-core/commands/tpm2_key_protector/args.c b/grub-core/commands/tpm2_key_protector/args.c
new file mode 100644
index 000000000..c58cbe307
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/args.c
@@ -0,0 +1,129 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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 "tpm2_args.h"
+
+grub_err_t
+grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs,
+ grub_uint8_t *pcr_count)
+{
+ char *current_pcr = value;
+ char *next_pcr;
+ const char *pcr_end;
+ grub_uint64_t pcr;
+ grub_uint8_t i;
+
+ if (grub_strlen (value) == 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *pcr_count = 0;
+ for (i = 0; i < TPM_MAX_PCRS; i++)
+ {
+ next_pcr = grub_strchr (current_pcr, ',');
+ if (next_pcr == current_pcr)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Empty entry in PCR list");
+ if (next_pcr != NULL)
+ *next_pcr = '\0';
+
+ grub_errno = GRUB_ERR_NONE;
+ pcr = grub_strtoul (current_pcr, &pcr_end, 10);
+ if (*current_pcr == '\0' || *pcr_end != '\0')
+ return grub_error (GRUB_ERR_BAD_NUMBER, "Entry '%s' in PCR list is not a number", current_pcr);
+
+ if (pcr > TPM_MAX_PCRS)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Entry %" PRIuGRUB_UINT64_T " in PCR list is too large to be a PCR number, PCR numbers range from 0 to %u", pcr, TPM_MAX_PCRS);
+
+ pcrs[i] = (grub_uint8_t) pcr;
+ ++(*pcr_count);
+
+ if (next_pcr == NULL)
+ break;
+
+ current_pcr = next_pcr + 1;
+ if (*current_pcr == '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Trailing comma at the end of PCR list");
+ }
+
+ if (i == TPM_MAX_PCRS)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Too many PCRs in PCR list, the maximum number of PCRs is %u", TPM_MAX_PCRS);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2_protector_parse_asymmetric (const char *value,
+ grub_srk_type_t *srk_type)
+{
+ if (grub_strcasecmp (value, "ECC") == 0 ||
+ grub_strcasecmp (value, "ECC_NIST_P256") == 0)
+ {
+ srk_type->type = TPM_ALG_ECC;
+ srk_type->detail.ecc_curve = TPM_ECC_NIST_P256;
+ }
+ else if (grub_strcasecmp (value, "RSA") == 0 ||
+ grub_strcasecmp (value, "RSA2048") == 0)
+ {
+ srk_type->type = TPM_ALG_RSA;
+ srk_type->detail.rsa_bits = 2048;
+ }
+ else
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid asymmetric key type", value);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID_t *bank)
+{
+ if (grub_strcasecmp (value, "SHA1") == 0)
+ *bank = TPM_ALG_SHA1;
+ else if (grub_strcasecmp (value, "SHA256") == 0)
+ *bank = TPM_ALG_SHA256;
+ else if (grub_strcasecmp (value, "SHA384") == 0)
+ *bank = TPM_ALG_SHA384;
+ else if (grub_strcasecmp (value, "SHA512") == 0)
+ *bank = TPM_ALG_SHA512;
+ else
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid PCR bank", value);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle)
+{
+ grub_uint64_t num;
+ const char *str_end;
+
+ grub_errno = GRUB_ERR_NONE;
+ num = grub_strtoul (value, &str_end, 0);
+ if (*value == '\0' || *str_end != '\0')
+ return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is not a number", value);
+
+ if (num > GRUB_UINT_MAX)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
+
+ *handle = (TPM_HANDLE_t) num;
+
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
new file mode 100644
index 000000000..909c3cc6a
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -0,0 +1,1153 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/extcmd.h>
+#include <grub/file.h>
+#include <grub/list.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/key_protector.h>
+
+#include <tss2_buffer.h>
+#include <tss2_types.h>
+#include <tss2_mu.h>
+
+#include "tpm2_args.h"
+#include "tpm2.h"
+#include "tpm2key.h"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef enum grub_tpm2_protector_mode
+{
+ GRUB_TPM2_PROTECTOR_MODE_UNSET,
+ GRUB_TPM2_PROTECTOR_MODE_SRK,
+ GRUB_TPM2_PROTECTOR_MODE_NV
+} grub_tpm2_protector_mode_t;
+
+enum grub_tpm2_protector_options
+{
+ OPTION_MODE,
+ OPTION_PCRS,
+ OPTION_BANK,
+ OPTION_TPM2KEY,
+ OPTION_KEYFILE,
+ OPTION_SRK,
+ OPTION_ASYMMETRIC,
+ OPTION_NVINDEX
+};
+
+struct grub_tpm2_protector_context
+{
+ grub_tpm2_protector_mode_t mode;
+ grub_uint8_t pcrs[TPM_MAX_PCRS];
+ grub_uint8_t pcr_count;
+ grub_srk_type_t srk_type;
+ TPM_ALG_ID_t bank;
+ const char *tpm2key;
+ const char *keyfile;
+ TPM_HANDLE_t srk;
+ TPM_HANDLE_t nv;
+};
+
+static const struct grub_arg_option grub_tpm2_protector_init_cmd_options[] =
+ {
+ /* Options for all modes */
+ {
+ .longarg = "mode",
+ .shortarg = 'm',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("Unseal key using SRK ('srk') (default) or retrieve it from an NV "
+ "Index ('nv')."),
+ },
+ {
+ .longarg = "pcrs",
+ .shortarg = 'p',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("Comma-separated list of PCRs used to authorize key release "
+ "e.g., '7,11'. (default: 7)"),
+ },
+ {
+ .longarg = "bank",
+ .shortarg = 'b',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("Bank of PCRs used to authorize key release: "
+ "SHA1, SHA256, SHA384 or SHA512. (default: SHA256)"),
+ },
+ /* SRK-mode options */
+ {
+ .longarg = "tpm2key",
+ .shortarg = 'T',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("In SRK mode, path to the key file in the TPM 2.0 Key File format "
+ "to unseal using the TPM (e.g., (hd0,gpt1)/boot/grub2/sealed.tpm)."),
+ },
+ {
+ .longarg = "keyfile",
+ .shortarg = 'k',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("In SRK mode, path to the key file in the raw format to unseal "
+ "using the TPM (e.g., (hd0,gpt1)/boot/grub2/sealed.key). "
+ "(Mainly for backward compatibility. Please use '--tpm2key'.)"),
+ },
+ {
+ .longarg = "srk",
+ .shortarg = 's',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("In SRK mode, the SRK handle if the SRK is persistent."),
+ },
+ {
+ .longarg = "asymmetric",
+ .shortarg = 'a',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("In SRK mode, the type of SRK: RSA (RSA2048) and ECC (ECC_NIST_P256)"
+ "(default: ECC)"),
+ },
+ /* NV Index-mode options */
+ {
+ .longarg = "nvindex",
+ .shortarg = 'n',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("Required in NV Index mode, the NV handle to read which must "
+ "readily exist on the TPM and which contains the key."),
+ },
+ /* End of list */
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_extcmd_t grub_tpm2_protector_init_cmd;
+static grub_extcmd_t grub_tpm2_protector_clear_cmd;
+static struct grub_tpm2_protector_context grub_tpm2_protector_ctx = {0};
+
+static grub_err_t
+tpm2_protector_srk_read_file (const char *filepath, void **buffer, grub_size_t *buffer_size)
+{
+ grub_file_t file;
+ grub_off_t file_size;
+ void *read_buffer;
+ grub_off_t read_n;
+ grub_err_t err;
+
+ /*
+ * Using GRUB_FILE_TYPE_SIGNATURE ensures we do not hash the keyfile into PCR9
+ * otherwise we'll never be able to predict the value of PCR9 at unseal time
+ */
+ file = grub_file_open (filepath, GRUB_FILE_TYPE_SIGNATURE);
+ if (file == NULL)
+ {
+ /* Push errno from grub_file_open() into the error message stack */
+ grub_error_push();
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "Could not open file: %s", filepath);
+ goto error;
+ }
+
+ file_size = grub_file_size (file);
+ if (file_size == 0)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_RANGE, "Could not read file size: %s", filepath);
+ goto error;
+ }
+
+ read_buffer = grub_malloc (file_size);
+ if (read_buffer == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate buffer for %s", filepath);
+ goto error;
+ }
+
+ read_n = grub_file_read (file, read_buffer, file_size);
+ if (read_n != file_size)
+ {
+ grub_free (read_buffer);
+ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "Could not retrieve file contents: %s", filepath);
+ goto error;
+ }
+
+ *buffer = read_buffer;
+ *buffer_size = file_size;
+
+ err = GRUB_ERR_NONE;
+
+ error:
+ if (file != NULL)
+ grub_file_close (file);
+
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_srk_unmarshal_keyfile (void *sealed_key,
+ grub_size_t sealed_key_size,
+ tpm2_sealed_key_t *sk)
+{
+ struct grub_tpm2_buffer buf;
+
+ grub_tpm2_buffer_init (&buf);
+ if (sealed_key_size > buf.cap)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Sealed key larger than %" PRIuGRUB_SIZE " bytes", buf.cap);
+
+ grub_memcpy (buf.data, sealed_key, sealed_key_size);
+ buf.size = sealed_key_size;
+
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public);
+ grub_Tss2_MU_TPM2B_PRIVATE_Unmarshal (&buf, &sk->private);
+
+ if (buf.error != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Malformed TPM wire key file");
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2_protector_srk_unmarshal_tpm2key (void *sealed_key,
+ grub_size_t sealed_key_size,
+ tpm2key_policy_t *policy_seq,
+ tpm2key_authpolicy_t *authpol_seq,
+ grub_uint8_t *rsaparent,
+ grub_uint32_t *parent,
+ tpm2_sealed_key_t *sk)
+{
+ asn1_node tpm2key = NULL;
+ grub_uint8_t rsaparent_tmp;
+ grub_uint32_t parent_tmp;
+ void *sealed_pub = NULL;
+ grub_size_t sealed_pub_size;
+ void *sealed_priv = NULL;
+ grub_size_t sealed_priv_size;
+ struct grub_tpm2_buffer buf;
+ grub_err_t err;
+
+ /*
+ * Start to parse the tpm2key file
+ * TPMKey ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
+ * policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL,
+ * secret [2] EXPLICIT OCTET STRING OPTIONAL,
+ * authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL,
+ * description [4] EXPLICIT UTF8String OPTIONAL,
+ * rsaParent [5] EXPLICIT BOOLEAN OPTIONAL,
+ * parent INTEGER,
+ * pubkey OCTET STRING,
+ * privkey OCTET STRING
+ * }
+ */
+ err = grub_tpm2key_start_parsing (&tpm2key, sealed_key, sealed_key_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /*
+ * Retrieve the policy sequence from 'policy'
+ * policy_seq will be NULL when 'policy' is not available
+ */
+ err = grub_tpm2key_get_policy_seq (tpm2key, policy_seq);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ /*
+ * Retrieve the authpolicy sequence from 'authPolicy'
+ * authpol_seq will be NULL when 'authPolicy' is not available
+ */
+ err = grub_tpm2key_get_authpolicy_seq (tpm2key, authpol_seq);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ /* Retrieve rsaParent */
+ err = grub_tpm2key_get_rsaparent (tpm2key, &rsaparent_tmp);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ *rsaparent = rsaparent_tmp;
+
+ /* Retrieve the parent handle */
+ err = grub_tpm2key_get_parent (tpm2key, &parent_tmp);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ /* The parent handle should be either PERMANENT or PERSISTENT. */
+ if (!TPM_HT_IS_PERMANENT (parent_tmp) && !TPM_HT_IS_PERSISTENT (parent_tmp))
+ {
+ err = GRUB_ERR_OUT_OF_RANGE;
+ goto error;
+ }
+
+ *parent = parent_tmp;
+
+ /* Retrieve the public part of the sealed key */
+ err = grub_tpm2key_get_pubkey (tpm2key, &sealed_pub, &sealed_pub_size);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ /* Retrieve the private part of the sealed key */
+ err = grub_tpm2key_get_privkey (tpm2key, &sealed_priv, &sealed_priv_size);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ /* Unmarshal the sealed key */
+ grub_tpm2_buffer_init (&buf);
+ if (sealed_pub_size + sealed_priv_size > buf.cap)
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "Sealed key larger than %" PRIuGRUB_SIZE " bytes", buf.cap);
+ goto error;
+ }
+
+ grub_tpm2_buffer_pack (&buf, sealed_pub, sealed_pub_size);
+ grub_tpm2_buffer_pack (&buf, sealed_priv, sealed_priv_size);
+
+ buf.offset = 0;
+
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public);
+ grub_Tss2_MU_TPM2B_PRIVATE_Unmarshal (&buf, &sk->private);
+
+ if (buf.error != 0)
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "Malformed TPM 2.0 key file");
+ goto error;
+ }
+
+ err = GRUB_ERR_NONE;
+
+ error:
+ /* End the parsing */
+ grub_tpm2key_end_parsing (tpm2key);
+ grub_free (sealed_pub);
+ grub_free (sealed_priv);
+
+ return err;
+}
+
+/* Check if the SRK exists in the specified handle */
+static grub_err_t
+tpm2_protector_srk_check (const TPM_HANDLE_t srk_handle)
+{
+ TPM_RC_t rc;
+ TPM2B_PUBLIC_t public;
+
+ /* Find SRK */
+ rc = grub_tpm2_readpublic (srk_handle, NULL, &public);
+ if (rc == TPM_RC_SUCCESS)
+ return GRUB_ERR_NONE;
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x)", srk_handle, rc);
+}
+
+/* Get the SRK with the template */
+static grub_err_t
+tpm2_protector_srk_get (const grub_srk_type_t srk_type,
+ const TPM_HANDLE_t parent,
+ TPM_HANDLE_t *srk_handle)
+{
+ TPM_RC_t rc;
+ TPMT_PUBLIC_PARMS_t parms = {0};
+ TPMS_AUTH_COMMAND_t authCommand = {0};
+ TPM2B_SENSITIVE_CREATE_t inSensitive = {0};
+ TPM2B_PUBLIC_t inPublic = {0};
+ TPM2B_DATA_t outsideInfo = {0};
+ TPML_PCR_SELECTION_t creationPcr = {0};
+ TPM2B_PUBLIC_t outPublic = {0};
+ TPM2B_CREATION_DATA_t creationData = {0};
+ TPM2B_DIGEST_t creationHash = {0};
+ TPMT_TK_CREATION_t creationTicket = {0};
+ TPM2B_NAME_t srkName = {0};
+ TPM_HANDLE_t tmp_handle = 0;
+
+ inPublic.publicArea.type = srk_type.type;
+ inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
+ inPublic.publicArea.objectAttributes.restricted = 1;
+ inPublic.publicArea.objectAttributes.userWithAuth = 1;
+ inPublic.publicArea.objectAttributes.decrypt = 1;
+ inPublic.publicArea.objectAttributes.fixedTPM = 1;
+ inPublic.publicArea.objectAttributes.fixedParent = 1;
+ inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1;
+ inPublic.publicArea.objectAttributes.noDA = 1;
+
+ if (srk_type.type == TPM_ALG_RSA)
+ {
+ inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
+ inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
+ inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
+ inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
+ inPublic.publicArea.parameters.rsaDetail.keyBits = srk_type.detail.rsa_bits;
+ inPublic.publicArea.parameters.rsaDetail.exponent = 0;
+ }
+ else if (srk_type.type == TPM_ALG_ECC)
+ {
+ inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
+ inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
+ inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
+ inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
+ inPublic.publicArea.parameters.eccDetail.curveID = srk_type.detail.ecc_curve;
+ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+ }
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown SRK algorithm");
+
+ /* Test the parameters before SRK generation */
+ parms.type = srk_type.type;
+ grub_memcpy (&parms.parameters, &inPublic.publicArea.parameters,
+ sizeof (TPMU_PUBLIC_PARMS_t));
+
+ rc = grub_tpm2_testparms (&parms, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported SRK template (TPM2_TestParms: 0x%x)", rc);
+
+ /* Create SRK */
+ authCommand.sessionHandle = TPM_RS_PW;
+ rc = grub_tpm2_createprimary (parent, &authCommand, &inSensitive, &inPublic,
+ &outsideInfo, &creationPcr, &tmp_handle, &outPublic,
+ &creationData, &creationHash, &creationTicket,
+ &srkName, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "Could not create SRK (TPM2_CreatePrimary: 0x%x)", rc);
+
+ *srk_handle = tmp_handle;
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Load the SRK from the persistent handle or create one with a given type of
+ * template, and then associate the sealed key with the SRK
+ * Return values:
+ * - GRUB_ERR_NONE: Everything is fine.
+ * - GRUB_ERR_BAD_ARGUMENT: The SRK doesn't match. Try another one.
+ * - Other: Something went wrong.
+ */
+static grub_err_t
+tpm2_protector_srk_load (const grub_srk_type_t srk_type,
+ const tpm2_sealed_key_t *sealed_key,
+ const TPM_HANDLE_t parent,
+ TPM_HANDLE_t *sealed_handle,
+ TPM_HANDLE_t *srk_handle)
+{
+ TPMS_AUTH_COMMAND_t authCmd = {0};
+ TPM2B_NAME_t name = {0};
+ TPM_RC_t rc;
+ grub_err_t err;
+
+ if (srk_handle == NULL)
+ return GRUB_ERR_BUG;
+
+ if (*srk_handle != 0)
+ {
+ err = tpm2_protector_srk_check (*srk_handle);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ else
+ {
+ err = tpm2_protector_srk_get (srk_type, parent, srk_handle);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ /* Load the sealed key and associate it with the SRK */
+ authCmd.sessionHandle = TPM_RS_PW;
+ rc = grub_tpm2_load (*srk_handle, &authCmd, &sealed_key->private, &sealed_key->public,
+ sealed_handle, &name, NULL);
+ /*
+ * If TPM2_Load returns (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1), then it
+ * implies the wrong SRK is used.
+ */
+ if (rc == (TPM_RC_INTEGRITY | TPM_RC_P | TPM_RC_1))
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "SRK not matched");
+ goto error;
+ }
+ else if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "Failed to load sealed key (TPM2_Load: 0x%x)", rc);
+ goto error;
+ }
+
+ return GRUB_ERR_NONE;
+
+ error:
+ if (!TPM_HT_IS_PERSISTENT (*srk_handle))
+ grub_tpm2_flushcontext (*srk_handle);
+
+ return err;
+}
+
+static const char *
+srk_type_to_name (grub_srk_type_t srk_type)
+{
+ if (srk_type.type == TPM_ALG_ECC && srk_type.detail.ecc_curve == TPM_ECC_NIST_P256)
+ return "ECC_NIST_P256";
+ else if (srk_type.type == TPM_ALG_RSA && srk_type.detail.rsa_bits == 2048)
+ return "RSA2048";
+
+ return "Unknown";
+}
+
+static grub_err_t
+tpm2_protector_load_key (const struct grub_tpm2_protector_context *ctx,
+ const tpm2_sealed_key_t *sealed_key,
+ const TPM_HANDLE_t parent_handle,
+ TPM_HANDLE_t *sealed_handle,
+ TPM_HANDLE_t *srk_handle)
+{
+ grub_err_t err;
+ int i;
+ grub_srk_type_t fallback_srks[] = {
+ {
+ .type = TPM_ALG_ECC,
+ .detail.ecc_curve = TPM_ECC_NIST_P256,
+ },
+ {
+ .type = TPM_ALG_RSA,
+ .detail.rsa_bits = 2048,
+ },
+ {
+ .type = TPM_ALG_ERROR,
+ }
+ };
+
+ /* Try the given persistent SRK if exists */
+ if (*srk_handle != 0)
+ {
+ err = tpm2_protector_srk_load (ctx->srk_type, sealed_key,
+ parent_handle, sealed_handle,
+ srk_handle);
+ if (err != GRUB_ERR_BAD_ARGUMENT)
+ return err;
+
+ grub_print_error ();
+ grub_printf ("Trying the specified SRK algorithm: %s\n", srk_type_to_name (ctx->srk_type));
+ grub_errno = GRUB_ERR_NONE;
+ *srk_handle = 0;
+ }
+
+ /* Try the specified algorithm for the SRK template */
+ if (*srk_handle == 0)
+ {
+ err = tpm2_protector_srk_load (ctx->srk_type, sealed_key,
+ parent_handle, sealed_handle,
+ srk_handle);
+ if (err != GRUB_ERR_BAD_ARGUMENT)
+ return err;
+
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ *srk_handle = 0;
+ }
+
+ /* Try all the fallback SRK templates */
+ for (i = 0; fallback_srks[i].type != TPM_ALG_ERROR; i++)
+ {
+ /* Skip the specified algorithm */
+ if (fallback_srks[i].type == ctx->srk_type.type &&
+ (fallback_srks[i].detail.rsa_bits == ctx->srk_type.detail.rsa_bits ||
+ fallback_srks[i].detail.ecc_curve == ctx->srk_type.detail.ecc_curve))
+ continue;
+
+ grub_printf ("Trying fallback %s template\n", srk_type_to_name (fallback_srks[i]));
+
+ *srk_handle = 0;
+
+ err = tpm2_protector_srk_load (fallback_srks[i], sealed_key,
+ parent_handle, sealed_handle,
+ srk_handle);
+ if (err != GRUB_ERR_BAD_ARGUMENT)
+ return err;
+
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION_t session, struct grub_tpm2_buffer *cmd_buf)
+{
+ TPM2B_DIGEST_t pcr_digest;
+ TPML_PCR_SELECTION_t pcr_sel;
+ TPM_RC_t rc;
+
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (cmd_buf, &pcr_digest);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Unmarshal (cmd_buf, &pcr_sel);
+ if (cmd_buf->error != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to unmarshal CommandPolicy for TPM2_PolicyPCR");
+
+ rc = grub_tpm2_policypcr (session, NULL, &pcr_digest, &pcr_sel, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x)", rc);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION_t session)
+{
+ struct grub_tpm2_buffer buf;
+ grub_err_t err;
+
+ grub_tpm2_buffer_init (&buf);
+ if (policy->cmd_policy_len > buf.cap)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "CommandPolicy larger than TPM buffer");
+
+ grub_memcpy (buf.data, policy->cmd_policy, policy->cmd_policy_len);
+ buf.size = policy->cmd_policy_len;
+
+ switch (policy->cmd_code)
+ {
+ case TPM_CC_PolicyPCR:
+ err = tpm2_protector_policypcr (session, &buf);
+ break;
+ default:
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown TPM Command: 0x%x", policy->cmd_code);
+ }
+
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_enforce_policy_seq (tpm2key_policy_t policy_seq, TPMI_SH_AUTH_SESSION_t session)
+{
+ tpm2key_policy_t policy;
+ grub_err_t err;
+
+ FOR_LIST_ELEMENTS (policy, policy_seq)
+ {
+ err = tpm2_protector_enforce_policy (policy, session);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2_protector_simple_policy_seq (const struct grub_tpm2_protector_context *ctx,
+ tpm2key_policy_t *policy_seq)
+{
+ tpm2key_policy_t policy = NULL;
+ struct grub_tpm2_buffer buf;
+ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
+ .hash = ctx->bank,
+ .sizeOfSelect = 3,
+ .pcrSelect = {0}
+ },
+ }
+ };
+ grub_uint8_t i;
+ grub_err_t err;
+
+ if (policy_seq == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ grub_tpm2_buffer_init (&buf);
+
+ for (i = 0; i < ctx->pcr_count; i++)
+ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], ctx->pcrs[i]);
+
+ grub_tpm2_buffer_pack_u16 (&buf, 0);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (&buf, &pcr_sel);
+
+ if (buf.error != 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ policy = grub_malloc (sizeof(struct tpm2key_policy));
+ if (policy == NULL)
+ {
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ goto error;
+ }
+ policy->cmd_code = TPM_CC_PolicyPCR;
+ policy->cmd_policy = grub_malloc (buf.size);
+ if (policy->cmd_policy == NULL)
+ {
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ goto error;
+ }
+ grub_memcpy (policy->cmd_policy, buf.data, buf.size);
+ policy->cmd_policy_len = buf.size;
+
+ grub_list_push (GRUB_AS_LIST_P (policy_seq), GRUB_AS_LIST (policy));
+
+ return GRUB_ERR_NONE;
+
+ error:
+ grub_free (policy);
+
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE_t sealed_handle,
+ grub_uint8_t **key, grub_size_t *key_size)
+{
+ TPMS_AUTH_COMMAND_t authCmd = {0};
+ TPM2B_SENSITIVE_DATA_t data;
+ TPM2B_NONCE_t nonceCaller = {0};
+ TPMT_SYM_DEF_t symmetric = {0};
+ TPMI_SH_AUTH_SESSION_t session;
+ grub_uint8_t *key_out;
+ TPM_RC_t rc;
+ grub_err_t err;
+
+ /* Start Auth Session */
+ nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
+ symmetric.algorithm = TPM_ALG_NULL;
+ rc = grub_tpm2_startauthsession (TPM_RH_NULL, TPM_RH_NULL, NULL, &nonceCaller, NULL,
+ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256,
+ &session, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to start auth session (TPM2_StartAuthSession: 0x%x)", rc);
+
+ /* Enforce the policy command sequence */
+ err = tpm2_protector_enforce_policy_seq (policy_seq, session);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
+ /* Unseal Sealed Key */
+ authCmd.sessionHandle = session;
+ rc = grub_tpm2_unseal (sealed_handle, &authCmd, &data, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "Failed to unseal sealed key (TPM2_Unseal: 0x%x)", rc);
+ goto error;
+ }
+
+ /* Epilogue */
+ key_out = grub_malloc (data.size);
+ if (key_out == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "No memory left to allocate unlock key buffer");
+ goto error;
+ }
+
+ grub_memcpy (key_out, data.buffer, data.size);
+
+ *key = key_out;
+ *key_size = data.size;
+
+ err = GRUB_ERR_NONE;
+
+ error:
+ grub_tpm2_flushcontext (session);
+
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx,
+ grub_uint8_t **key, grub_size_t *key_size)
+{
+ tpm2_sealed_key_t sealed_key = {0};
+ void *file_bytes = NULL;
+ grub_size_t file_size = 0;
+ grub_uint8_t rsaparent = 0;
+ TPM_HANDLE_t parent_handle = 0;
+ TPM_HANDLE_t srk_handle = 0;
+ TPM_HANDLE_t sealed_handle = 0;
+ tpm2key_policy_t policy_seq = NULL;
+ tpm2key_authpolicy_t authpol = NULL;
+ tpm2key_authpolicy_t authpol_seq = NULL;
+ grub_err_t err;
+
+ /*
+ * Retrieve sealed key, parent handle, policy sequence, and authpolicy
+ * sequence from the key file
+ */
+ if (ctx->tpm2key != NULL)
+ {
+ err = tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes,
+ &file_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = tpm2_protector_srk_unmarshal_tpm2key (file_bytes,
+ file_size,
+ &policy_seq,
+ &authpol_seq,
+ &rsaparent,
+ &parent_handle,
+ &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+
+ if (rsaparent == 1)
+ {
+ struct grub_tpm2_protector_context *ctx_w;
+
+ /* Overwrite the SRK type as noted in the key */
+ ctx_w = (struct grub_tpm2_protector_context *)ctx;
+ ctx_w->srk_type.type = TPM_ALG_RSA;
+ ctx_w->srk_type.detail.rsa_bits = 2048;
+ }
+ }
+ else
+ {
+ err = tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes, &file_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ parent_handle = TPM_RH_OWNER;
+ err = tpm2_protector_srk_unmarshal_keyfile (file_bytes, file_size, &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+ }
+
+ /* Set the SRK handle if it is specified with '--srk' or inside the key file */
+ if (ctx->srk != 0)
+ srk_handle = ctx->srk;
+ else if (TPM_HT_IS_PERSISTENT (parent_handle))
+ srk_handle = parent_handle;
+
+ /* Load the sealed key into TPM and associate it with the SRK */
+ err = tpm2_protector_load_key (ctx, &sealed_key, parent_handle, &sealed_handle, &srk_handle);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+
+ /*
+ * Set err to an error code to trigger the standalone policy sequence
+ * if there is no authpolicy sequence
+ */
+ err = GRUB_ERR_READ_ERROR;
+
+ /* Iterate the authpolicy sequence to find one that unseals the key */
+ FOR_LIST_ELEMENTS (authpol, authpol_seq)
+ {
+ err = tpm2_protector_unseal (authpol->policy_seq, sealed_handle, key, key_size);
+ if (err == GRUB_ERR_NONE)
+ break;
+
+ /*
+ * Push the error message into the grub_error stack
+ * Note: The grub_error stack may overflow if there are too many policy
+ * sequences. Anyway, we still can keep the error messages from
+ * the first few policy sequences which are usually most likely to
+ * unseal the key.
+ */
+ grub_error_push();
+ }
+
+ /* Give the standalone policy sequence a try */
+ if (err != GRUB_ERR_NONE)
+ {
+ /*
+ * Create a basic policy sequence based on the given PCR selection if the
+ * key file doesn't provide one
+ */
+ if (policy_seq == NULL)
+ {
+ err = tpm2_protector_simple_policy_seq (ctx, &policy_seq);
+ if (err != GRUB_ERR_NONE)
+ goto exit2;
+ }
+
+ err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size);
+ }
+
+ /* Pop error messages on success */
+ if (err == GRUB_ERR_NONE)
+ while (grub_error_pop ());
+
+ exit2:
+ grub_tpm2_flushcontext (sealed_handle);
+
+ if (!TPM_HT_IS_PERSISTENT (srk_handle))
+ grub_tpm2_flushcontext (srk_handle);
+
+ exit1:
+ grub_tpm2key_free_policy_seq (policy_seq);
+ grub_tpm2key_free_authpolicy_seq (authpol_seq);
+ grub_free (file_bytes);
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx __attribute__ ((unused)),
+ grub_uint8_t **key __attribute__ ((unused)),
+ grub_size_t *key_size __attribute__ ((unused)))
+{
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "NV Index mode is not implemented yet");
+}
+
+static grub_err_t
+tpm2_protector_recover (const struct grub_tpm2_protector_context *ctx,
+ grub_uint8_t **key, grub_size_t *key_size)
+{
+ switch (ctx->mode)
+ {
+ case GRUB_TPM2_PROTECTOR_MODE_SRK:
+ return tpm2_protector_srk_recover (ctx, key, key_size);
+ case GRUB_TPM2_PROTECTOR_MODE_NV:
+ return tpm2_protector_nv_recover (ctx, key, key_size);
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+}
+
+static grub_err_t
+tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t *key_size)
+{
+ /* Expect a call to tpm2_protector_init before anybody tries to use us */
+ if (grub_tpm2_protector_ctx.mode == GRUB_TPM2_PROTECTOR_MODE_UNSET)
+ return grub_error (GRUB_ERR_INVALID_COMMAND, "Cannot use TPM2 key protector without initializing it, call tpm2_protector_init first");
+
+ if (key == NULL || key_size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ return tpm2_protector_recover (&grub_tpm2_protector_ctx, key, key_size);
+}
+
+static grub_err_t
+tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx)
+{
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_UNSET)
+ ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+
+ /* Checks for SRK mode */
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK &&
+ (ctx->keyfile == NULL && ctx->tpm2key == NULL))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In SRK mode, a key file must be specified: --tpm2key/-T or --keyfile/-k");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK &&
+ (ctx->keyfile != NULL && ctx->tpm2key != NULL))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In SRK mode, please specify a key file with only --tpm2key/-T or --keyfile/-k");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->nv != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In SRK mode, an NV Index cannot be specified");
+
+ /* Checks for NV mode */
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->nv == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, an NV Index must be specified: --nvindex or -n");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV &&
+ (ctx->tpm2key != NULL || ctx->keyfile != NULL))
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, a keyfile cannot be specified");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->srk != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, an SRK cannot be specified");
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV &&
+ ctx->srk_type.type != TPM_ALG_ERROR)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "In NV Index mode, an asymmetric key type cannot be specified");
+
+ /* Defaults assignment */
+ if (ctx->bank == TPM_ALG_ERROR)
+ ctx->bank = TPM_ALG_SHA256;
+
+ if (ctx->pcr_count == 0)
+ {
+ ctx->pcrs[0] = 7;
+ ctx->pcr_count = 1;
+ }
+
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK &&
+ ctx->srk_type.type == TPM_ALG_ERROR)
+ {
+ ctx->srk_type.type = TPM_ALG_ECC;
+ ctx->srk_type.detail.ecc_curve = TPM_ECC_NIST_P256;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2_protector_parse_file (const char *value, const char **file)
+{
+ if (grub_strlen (value) == 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *file = grub_strdup (value);
+ if (*file == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "No memory to duplicate file path");
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2_protector_parse_mode (const char *value, grub_tpm2_protector_mode_t *mode)
+{
+ if (grub_strcmp (value, "srk") == 0)
+ *mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+ else if (grub_strcmp (value, "nv") == 0)
+ *mode = GRUB_TPM2_PROTECTOR_MODE_NV;
+ else
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid TPM2 key protector mode", value);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int argc,
+ char **args __attribute__ ((unused)))
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_err_t err;
+
+ if (argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "The TPM2 key protector does not accept any non-option arguments (i.e., like -o and/or --option only)");
+
+ grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx));
+
+ if (state[OPTION_MODE].set) /* mode */
+ {
+ err = tpm2_protector_parse_mode (state[OPTION_MODE].arg, &grub_tpm2_protector_ctx.mode);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_PCRS].set) /* pcrs */
+ {
+ err = grub_tpm2_protector_parse_pcrs (state[OPTION_PCRS].arg,
+ grub_tpm2_protector_ctx.pcrs,
+ &grub_tpm2_protector_ctx.pcr_count);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_BANK].set) /* bank */
+ {
+ err = grub_tpm2_protector_parse_bank (state[OPTION_BANK].arg,
+ &grub_tpm2_protector_ctx.bank);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_TPM2KEY].set) /* tpm2key */
+ {
+ err = tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
+ &grub_tpm2_protector_ctx.tpm2key);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_KEYFILE].set) /* keyfile */
+ {
+ err = tpm2_protector_parse_file (state[OPTION_KEYFILE].arg,
+ &grub_tpm2_protector_ctx.keyfile);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_SRK].set) /* srk */
+ {
+ err = grub_tpm2_protector_parse_tpm_handle (state[OPTION_SRK].arg,
+ &grub_tpm2_protector_ctx.srk);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_ASYMMETRIC].set) /* asymmetric */
+ {
+ err = grub_tpm2_protector_parse_asymmetric (state[OPTION_ASYMMETRIC].arg,
+ &grub_tpm2_protector_ctx.srk_type);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (state[OPTION_NVINDEX].set) /* nvindex */
+ {
+ err = grub_tpm2_protector_parse_tpm_handle (state[OPTION_NVINDEX].arg,
+ &grub_tpm2_protector_ctx.nv);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ err = tpm2_protector_check_args (&grub_tpm2_protector_ctx);
+
+ /* This command only initializes the protector, so nothing else to do. */
+
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_clear_cmd_handler (grub_extcmd_context_t ctxt __attribute__ ((unused)),
+ int argc, char **args __attribute__ ((unused)))
+{
+ if (argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "tpm2_key_protector_clear accepts no arguments");
+
+ grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+ grub_memset (&grub_tpm2_protector_ctx, 0, sizeof (grub_tpm2_protector_ctx));
+
+ return GRUB_ERR_NONE;
+}
+
+static struct grub_key_protector grub_tpm2_key_protector =
+ {
+ .name = "tpm2",
+ .recover_key = tpm2_protector_recover_key
+ };
+
+GRUB_MOD_INIT (tpm2_key_protector)
+{
+ grub_tpm2_protector_init_cmd =
+ grub_register_extcmd ("tpm2_key_protector_init",
+ tpm2_protector_init_cmd_handler, 0,
+ N_("[-m mode] "
+ "[-p pcr_list] "
+ "[-b pcr_bank] "
+ "[-T tpm2_key_file_path] "
+ "[-k sealed_key_file_path] "
+ "[-s srk_handle] "
+ "[-a asymmetric_key_type] "
+ "[-n nv_index]"),
+ N_("Initialize the TPM2 key protector."),
+ grub_tpm2_protector_init_cmd_options);
+ grub_tpm2_protector_clear_cmd =
+ grub_register_extcmd ("tpm2_key_protector_clear",
+ tpm2_protector_clear_cmd_handler, 0, NULL,
+ N_("Clear the TPM2 key protector if previously initialized."),
+ NULL);
+ grub_key_protector_register (&grub_tpm2_key_protector);
+}
+
+GRUB_MOD_FINI (tpm2_key_protector)
+{
+ grub_free ((void *) grub_tpm2_protector_ctx.keyfile);
+
+ grub_key_protector_unregister (&grub_tpm2_key_protector);
+ grub_unregister_extcmd (grub_tpm2_protector_clear_cmd);
+ grub_unregister_extcmd (grub_tpm2_protector_init_cmd);
+}
diff --git a/grub-core/commands/tpm2_key_protector/tpm2.h b/grub-core/commands/tpm2_key_protector/tpm2.h
new file mode 100644
index 000000000..1c1d871b4
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/tpm2.h
@@ -0,0 +1,36 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_TPM2_HEADER
+#define GRUB_TPM2_TPM2_HEADER 1
+
+#include <tss2_types.h>
+#include <tss2_structs.h>
+#include <tpm2_cmd.h>
+
+/* Well-Known Windows SRK handle */
+#define TPM2_SRK_HANDLE 0x81000001
+
+struct tpm2_sealed_key {
+ TPM2B_PUBLIC_t public;
+ TPM2B_PRIVATE_t private;
+};
+typedef struct tpm2_sealed_key tpm2_sealed_key_t;
+
+#endif /* ! GRUB_TPM2_TPM2_HEADER */
diff --git a/grub-core/commands/tpm2_key_protector/tpm2_args.h b/grub-core/commands/tpm2_key_protector/tpm2_args.h
new file mode 100644
index 000000000..7cf1ebc46
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/tpm2_args.h
@@ -0,0 +1,49 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_INTERNAL_ARGS_HEADER
+#define GRUB_TPM2_INTERNAL_ARGS_HEADER 1
+
+#include <grub/err.h>
+
+#include "tpm2.h"
+
+struct grub_srk_type
+{
+ TPMI_ALG_PUBLIC_t type;
+ union {
+ TPM_KEY_BITS_t rsa_bits;
+ TPM_ECC_CURVE_t ecc_curve;
+ } detail;
+};
+typedef struct grub_srk_type grub_srk_type_t;
+
+grub_err_t
+grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs, grub_uint8_t *pcr_count);
+
+grub_err_t
+grub_tpm2_protector_parse_asymmetric (const char *value, grub_srk_type_t *srk_type);
+
+grub_err_t
+grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID_t *bank);
+
+grub_err_t
+grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle);
+
+#endif /* ! GRUB_TPM2_INTERNAL_ARGS_HEADER */
diff --git a/grub-core/commands/tpm2_key_protector/tpm2key.asn b/grub-core/commands/tpm2_key_protector/tpm2key.asn
new file mode 100644
index 000000000..e1fb51545
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/tpm2key.asn
@@ -0,0 +1,49 @@
+--
+-- GRUB: GRand Unified Bootloader
+-- Copyright (C) 2024 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/>.
+--
+-- This file describes TPM 2.0 Key File format for libtasn1.
+-- To generate tpm2key_asn1_tab.c: asn1Parser tpm2key.asn
+--
+TPM2KEY {}
+DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+TPMPolicy ::= SEQUENCE {
+ CommandCode [0] EXPLICIT INTEGER,
+ CommandPolicy [1] EXPLICIT OCTET STRING
+}
+
+TPMAuthPolicy ::= SEQUENCE {
+ Name [0] EXPLICIT UTF8String OPTIONAL,
+ Policy [1] EXPLICIT SEQUENCE OF TPMPolicy
+}
+
+TPMKey ::= SEQUENCE {
+ type OBJECT IDENTIFIER,
+ emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
+ policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL,
+ secret [2] EXPLICIT OCTET STRING OPTIONAL,
+ authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL,
+ description [4] EXPLICIT UTF8String OPTIONAL,
+ rsaParent [5] EXPLICIT BOOLEAN OPTIONAL,
+ parent INTEGER,
+ pubkey OCTET STRING,
+ privkey OCTET STRING
+}
+
+END
diff --git a/grub-core/commands/tpm2_key_protector/tpm2key.c b/grub-core/commands/tpm2_key_protector/tpm2key.c
new file mode 100644
index 000000000..7b188a93b
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/tpm2key.c
@@ -0,0 +1,499 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2023 SUSE LLC
+ * Copyright (C) 2024 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/list.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+#include <tss2_buffer.h>
+
+#include "tpm2key.h"
+
+extern asn1_static_node tpm2key_asn1_tab[];
+const char *sealed_key_oid = "2.23.133.10.1.5";
+
+static int
+asn1_allocate_and_read (asn1_node node, const char *name, void **content, grub_size_t *content_size)
+{
+ grub_uint8_t *tmpstr = NULL;
+ int tmpstr_size = 0;
+ int ret;
+
+ if (content == NULL)
+ return ASN1_MEM_ERROR;
+
+ ret = asn1_read_value (node, name, NULL, &tmpstr_size);
+ if (ret != ASN1_MEM_ERROR)
+ return ret;
+
+ tmpstr = grub_malloc (tmpstr_size);
+ if (tmpstr == NULL)
+ return ASN1_MEM_ERROR;
+
+ ret = asn1_read_value (node, name, tmpstr, &tmpstr_size);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+
+ *content = tmpstr;
+ *content_size = tmpstr_size;
+
+ return ASN1_SUCCESS;
+}
+
+static int
+asn1_read_uint32 (asn1_node node, const char *name, grub_uint32_t *out)
+{
+ grub_uint32_t tmp = 0;
+ grub_uint8_t *ptr;
+ void *data = NULL;
+ grub_size_t data_size;
+ int ret;
+
+ ret = asn1_allocate_and_read (node, name, &data, &data_size);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+
+ /*
+ * ASN.1 INTEGER is encoded in the following format:
+ *
+ * TAG LENGTH OCTECTS
+ *
+ * The integer TAG is 02 and LENGTH is the number of followed OCTECTS in
+ * big endian. For example:
+ *
+ * 0x1: 02 01 01
+ * 0xabcd: 02 02 ab cd
+ *
+ * To decribe 0x1, it only takes 1 octect, so LENGTH is 0x01 and the
+ * octect is 0x01. On the other hand, 0xabcd requires 2 octects: 'ab" and
+ * 'cd', so LENGTH is 0x02.
+ *
+ * This function only expects a uint32 integer, so it rejects any integer
+ * containing more than 4 octects.
+ */
+ if (data_size > 4)
+ {
+ ret = ASN1_MEM_ERROR;
+ goto error;
+ }
+
+ /* Copy the octects into 'tmp' to make it a big-endian uint32 */
+ ptr = (grub_uint8_t *) &tmp + (4 - data_size);
+ grub_memcpy (ptr, data, data_size);
+
+ /* Convert the big-endian integer to host uint32 */
+ tmp = grub_be_to_cpu32 (tmp);
+
+ *out = tmp;
+ error:
+ if (data)
+ grub_free (data);
+ return ret;
+}
+
+grub_err_t
+grub_tpm2key_start_parsing (asn1_node *parsed_tpm2key, void *data, grub_size_t size)
+{
+ asn1_node tpm2key;
+ asn1_node tpm2key_asn1 = NULL;
+ void *type_oid = NULL;
+ grub_size_t type_oid_size = 0;
+ void *empty_auth = NULL;
+ grub_size_t empty_auth_size = 0;
+ int tmp_size = 0;
+ int ret;
+ grub_err_t err;
+
+ /*
+ * TPMKey ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
+ * policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL,
+ * secret [2] EXPLICIT OCTET STRING OPTIONAL,
+ * authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL,
+ * description [4] EXPLICIT UTF8String OPTIONAL,
+ * rsaParent [5] EXPLICIT BOOLEAN OPTIONAL,
+ * parent INTEGER,
+ * pubkey OCTET STRING,
+ * privkey OCTET STRING
+ * }
+ */
+ ret = asn1_array2tree (tpm2key_asn1_tab, &tpm2key_asn1, NULL);
+ if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to parse TPM2KEY ASN.1 array");
+
+ ret = asn1_create_element (tpm2key_asn1, "TPM2KEY.TPMKey", &tpm2key);
+ if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to create TPM2KEY.TPMKey");
+
+ ret = asn1_der_decoding (&tpm2key, data, size, NULL);
+ if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to decode TPM2KEY DER");
+
+ /* Check if 'type' is Sealed Key or not */
+ ret = asn1_allocate_and_read (tpm2key, "type", &type_oid, &type_oid_size);
+ if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "Not a valid TPM2KEY file");
+
+ if (grub_memcmp (sealed_key_oid, type_oid, type_oid_size) != 0)
+ {
+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "Not a valid TPM2KEY file");
+ goto error;
+ }
+
+ /* 'emptyAuth' must be 'TRUE' since we don't support password authorization */
+ ret = asn1_allocate_and_read (tpm2key, "emptyAuth", &empty_auth, &empty_auth_size);
+ if (ret != ASN1_SUCCESS || grub_strncmp ("TRUE", empty_auth, empty_auth_size) != 0)
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "emptyAuth not TRUE");
+ goto error;
+ }
+
+ /* 'secret' should not be in a sealed key */
+ ret = asn1_read_value (tpm2key, "secret", NULL, &tmp_size);
+ if (ret != ASN1_ELEMENT_NOT_FOUND)
+ {
+ err = grub_error (GRUB_ERR_BAD_ARGUMENT, "\"secret\" not allowed for Sealed Key");
+ goto error;
+ }
+
+ *parsed_tpm2key = tpm2key;
+
+ err = GRUB_ERR_NONE;
+
+ error:
+ grub_free (type_oid);
+ grub_free (empty_auth);
+
+ return err;
+}
+
+void
+grub_tpm2key_end_parsing (asn1_node tpm2key)
+{
+ asn1_delete_structure (&tpm2key);
+ tpm2key = NULL;
+}
+
+grub_err_t
+grub_tpm2key_get_rsaparent (asn1_node tpm2key, grub_uint8_t *rsaparent)
+{
+ void *bool_str = NULL;
+ grub_size_t bool_str_size = 0;
+ int ret;
+
+ if (rsaparent == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "NULL pointer detected");
+
+ if (tpm2key == NULL)
+ return grub_error (GRUB_ERR_READ_ERROR, "Invalid parent node");
+
+ ret = asn1_allocate_and_read (tpm2key, "rsaParent", &bool_str, &bool_str_size);
+ if (ret == ASN1_SUCCESS)
+ {
+ if (grub_strncmp ("TRUE", bool_str, bool_str_size) == 0)
+ *rsaparent = 1;
+ else
+ *rsaparent = 0;
+ }
+ else if (ret == ASN1_ELEMENT_NOT_FOUND)
+ *rsaparent = 0;
+ else
+ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve rsaParent");
+
+ grub_free (bool_str);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2key_get_parent (asn1_node tpm2key, grub_uint32_t *parent)
+{
+ int ret;
+
+ if (parent == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "NULL pointer detected");
+
+ if (tpm2key == NULL)
+ return grub_error (GRUB_ERR_READ_ERROR, "Invalid parent node");
+
+ ret = asn1_read_uint32 (tpm2key, "parent", parent);
+ if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve parent");
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+tpm2key_get_octstring (asn1_node tpm2key, const char *name, void **data, grub_size_t *size)
+{
+ int ret;
+
+ if (name == NULL || data == NULL || size == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid parameter(s)");
+
+ if (tpm2key == NULL)
+ return grub_error (GRUB_ERR_READ_ERROR, "Invalid %s node", name);
+
+ ret = asn1_allocate_and_read (tpm2key, name, data, size);
+ if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve %s", name);
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tpm2key_get_pubkey (asn1_node tpm2key, void **data, grub_size_t *size)
+{
+ return tpm2key_get_octstring (tpm2key, "pubkey", data, size);
+}
+
+grub_err_t
+grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t *size)
+{
+ return tpm2key_get_octstring (tpm2key, "privkey", data, size);
+}
+
+/*
+ * The maximum and minimum number of elements for 'policy' and 'authPolicy' sequences
+ *
+ * Although there is no limit for the number of sequences elements, we set the upper
+ * bound to 99 to make it easier to implement the code.
+ *
+ * Any 'policy' or 'authPolicy' contains more than 99 commands/policies would become
+ * extremely complex to manage so it is impractical to support such use case.
+ */
+#define TPM2KEY_ELEMENTS_MAX 99
+#define TPM2KEY_ELEMENTS_MIN 1
+
+/*
+ * The string to fetch 'Policy' from 'authPolicy':
+ * authPolicy.?XX.Policy
+ */
+#define AUTHPOLICY_POL_MAX_STR "authPolicy.?XX.Policy"
+#define AUTHPOLICY_POL_MAX (sizeof (AUTHPOLICY_POL_MAX_STR))
+
+/*
+ * Expected strings for CommandCode and CommandPolicy:
+ * policy.?XX.CommandCode
+ * policy.?XX.CommandPolicy
+ * authPolicy.?XX.Policy.?YY.CommandCode
+ * authPolicy.?XX.Policy.?YY.CommandPolicy
+ */
+#define CMD_CODE_MAX_STR AUTHPOLICY_POL_MAX_STR".?YY.CommandCode"
+#define CMD_POL_MAX_STR AUTHPOLICY_POL_MAX_STR".?YY.CommandPolicy"
+#define CMD_CODE_MAX (sizeof (CMD_CODE_MAX_STR))
+#define CMD_POL_MAX (sizeof (CMD_POL_MAX_STR))
+
+static int
+tpm2key_get_policy_seq (asn1_node tpm2key, const char *prefix,
+ tpm2key_policy_t *policy_seq)
+{
+ tpm2key_policy_t tmp_seq = NULL;
+ tpm2key_policy_t policy = NULL;
+ int policy_n;
+ char cmd_code[CMD_CODE_MAX];
+ char cmd_pol[CMD_POL_MAX];
+ grub_size_t cmd_policy_len;
+ int i;
+ int ret;
+
+ ret = asn1_number_of_elements (tpm2key, prefix, &policy_n);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+
+ /*
+ * Limit the number of policy commands to two digits (99)
+ * Although there is no upper bound for the number of policy commands,
+ * in practice, it takes one or two policy commands to unseal the key,
+ * so the 99 commands limit is more than enough.
+ */
+ if (policy_n > TPM2KEY_ELEMENTS_MAX || policy_n < TPM2KEY_ELEMENTS_MIN)
+ return ASN1_VALUE_NOT_VALID;
+
+ /*
+ * Iterate the policy commands backwards since grub_list_push() prepends
+ * the item into the list.
+ */
+ for (i = policy_n; i >= 1; i--) {
+ policy = grub_zalloc (sizeof (struct tpm2key_policy));
+ if (policy == NULL)
+ {
+ ret = ASN1_MEM_ALLOC_ERROR;
+ goto error;
+ }
+ grub_snprintf (cmd_code, CMD_CODE_MAX, "%s.?%d.CommandCode", prefix, i);
+ grub_snprintf (cmd_pol, CMD_POL_MAX, "%s.?%d.CommandPolicy", prefix, i);
+
+ /* CommandCode [0] EXPLICIT INTEGER */
+ ret = asn1_read_uint32 (tpm2key, cmd_code, &policy->cmd_code);
+ if (ret != ASN1_SUCCESS)
+ return ret;
+
+ /* CommandPolicy [1] EXPLICIT OCTET STRING */
+ ret = tpm2key_get_octstring (tpm2key, cmd_pol, &policy->cmd_policy,
+ &cmd_policy_len);
+ if (ret != ASN1_SUCCESS)
+ {
+ goto error;
+ }
+ else if (cmd_policy_len > GRUB_TPM2_BUFFER_CAPACITY)
+ {
+ /*
+ * CommandPolicy is the marshalled parameters for the TPM command so
+ * it should not be larger than the maximum TPM2 buffer.
+ */
+ ret = ASN1_VALUE_NOT_VALID;
+ goto error;
+ }
+ policy->cmd_policy_len = (grub_uint16_t)cmd_policy_len;
+
+ /* Prepend the policy command into the sequence */
+ grub_list_push (GRUB_AS_LIST_P (&tmp_seq), GRUB_AS_LIST (policy));
+ }
+
+ *policy_seq = tmp_seq;
+
+ return ASN1_SUCCESS;
+
+ error:
+ if (policy != NULL)
+ {
+ grub_free (policy->cmd_policy);
+ grub_free (policy);
+ }
+ grub_tpm2key_free_policy_seq (tmp_seq);
+
+ return ret;
+}
+
+grub_err_t
+grub_tpm2key_get_policy_seq (asn1_node tpm2key, tpm2key_policy_t *policy_seq)
+{
+ int ret;
+
+ ret = tpm2key_get_policy_seq (tpm2key, "policy", policy_seq);
+ if (ret == ASN1_ELEMENT_NOT_FOUND)
+ {
+ /* "policy" is optional, so it may not be available */
+ *policy_seq = NULL;
+ return GRUB_ERR_NONE;
+ }
+ else if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve policy");
+
+ return GRUB_ERR_NONE;
+}
+
+void
+grub_tpm2key_free_policy_seq (tpm2key_policy_t policy_seq)
+{
+ tpm2key_policy_t policy;
+ tpm2key_policy_t next;
+
+ if (policy_seq == NULL)
+ return;
+
+ FOR_LIST_ELEMENTS_SAFE (policy, next, policy_seq)
+ {
+ grub_free (policy->cmd_policy);
+ grub_free (policy);
+ }
+}
+
+grub_err_t
+grub_tpm2key_get_authpolicy_seq (asn1_node tpm2key, tpm2key_authpolicy_t *authpol_seq)
+{
+ tpm2key_authpolicy_t tmp_seq = NULL;
+ tpm2key_authpolicy_t authpol = NULL;
+ int authpol_n;
+ char authpol_pol[AUTHPOLICY_POL_MAX];
+ int i;
+ int ret;
+ grub_err_t err;
+
+ ret = asn1_number_of_elements (tpm2key, "authPolicy", &authpol_n);
+ if (ret == ASN1_ELEMENT_NOT_FOUND)
+ {
+ /* "authPolicy" is optional, so it may not be available */
+ *authpol_seq = NULL;
+ return GRUB_ERR_NONE;
+ }
+ else if (ret != ASN1_SUCCESS)
+ return grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve authPolicy");
+
+ /* Limit the number of authPolicy elements to two digits (99) */
+ if (authpol_n > TPM2KEY_ELEMENTS_MAX || authpol_n < TPM2KEY_ELEMENTS_MIN)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid number of authPolicy elements");
+
+ /*
+ * Iterate the authPolicy elements backwards since grub_list_push() prepends
+ * the item into the list.
+ */
+ for (i = authpol_n; i >= 1; i--) {
+ authpol = grub_zalloc (sizeof (struct tpm2key_authpolicy));
+ if (authpol == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "Failed to allocate memory for authPolicy");
+ goto error;
+ }
+ grub_snprintf (authpol_pol, AUTHPOLICY_POL_MAX, "authPolicy.?%d.Policy", i);
+
+ ret = tpm2key_get_policy_seq (tpm2key, authpol_pol, &authpol->policy_seq);
+ if (ret != ASN1_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_READ_ERROR, "Failed to retrieve policy from authPolicy");
+ goto error;
+ }
+
+ /* Prepend the authPolicy element into the sequence */
+ grub_list_push (GRUB_AS_LIST_P (&tmp_seq), GRUB_AS_LIST (authpol));
+ }
+
+ *authpol_seq = tmp_seq;
+
+ return GRUB_ERR_NONE;
+
+ error:
+ if (authpol != NULL)
+ {
+ grub_tpm2key_free_policy_seq (authpol->policy_seq);
+ grub_free (authpol);
+ }
+
+ grub_tpm2key_free_authpolicy_seq (tmp_seq);
+
+ return err;
+}
+
+void
+grub_tpm2key_free_authpolicy_seq (tpm2key_authpolicy_t authpol_seq)
+{
+ tpm2key_authpolicy_t authpol;
+ tpm2key_authpolicy_t next;
+
+ if (authpol_seq == NULL)
+ return;
+
+ FOR_LIST_ELEMENTS_SAFE (authpol, next, authpol_seq)
+ {
+ grub_tpm2key_free_policy_seq (authpol->policy_seq);
+ grub_free (authpol);
+ }
+}
diff --git a/grub-core/commands/tpm2_key_protector/tpm2key.h b/grub-core/commands/tpm2_key_protector/tpm2key.h
new file mode 100644
index 000000000..cbd3f6119
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/tpm2key.h
@@ -0,0 +1,87 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2023 SUSE LLC
+ * Copyright (C) 2024 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/>.
+ */
+
+#ifndef GRUB_TPM2_TPM2KEY_HEADER
+#define GRUB_TPM2_TPM2KEY_HEADER 1
+
+#include <grub/types.h>
+#include <libtasn1.h>
+
+/*
+ * TPMPolicy ::= SEQUENCE {
+ * CommandCode [0] EXPLICIT INTEGER,
+ * CommandPolicy [1] EXPLICIT OCTET STRING
+ * }
+ */
+struct tpm2key_policy {
+ struct tpm2key_policy *next;
+ struct tpm2key_policy **prev;
+ grub_uint32_t cmd_code;
+ void *cmd_policy;
+ grub_uint16_t cmd_policy_len;
+};
+typedef struct tpm2key_policy *tpm2key_policy_t;
+
+/*
+ * TPMAuthPolicy ::= SEQUENCE {
+ * Name [0] EXPLICIT UTF8String OPTIONAL,
+ * Policy [1] EXPLICIT SEQUENCE OF TPMPolicy
+ * }
+ *
+ * Name is not a necessary part to unseal the key. Ignore it.
+ */
+struct tpm2key_authpolicy {
+ struct tpm2key_authpolicy *next;
+ struct tpm2key_authpolicy **prev;
+ /* char *name; */
+ tpm2key_policy_t policy_seq;
+};
+typedef struct tpm2key_authpolicy *tpm2key_authpolicy_t;
+
+grub_err_t
+grub_tpm2key_start_parsing (asn1_node *parsed_tpm2key, void *data, grub_size_t size);
+
+void
+grub_tpm2key_end_parsing (asn1_node tpm2key);
+
+grub_err_t
+grub_tpm2key_get_rsaparent (asn1_node tpm2key, grub_uint8_t *rsaparent);
+
+grub_err_t
+grub_tpm2key_get_parent (asn1_node tpm2key, grub_uint32_t *parent);
+
+grub_err_t
+grub_tpm2key_get_pubkey (asn1_node tpm2key, void **data, grub_size_t *size);
+
+grub_err_t
+grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t *size);
+
+grub_err_t
+grub_tpm2key_get_policy_seq (asn1_node tpm2key, tpm2key_policy_t *policy_seq);
+
+void
+grub_tpm2key_free_policy_seq (tpm2key_policy_t policy_seq);
+
+grub_err_t
+grub_tpm2key_get_authpolicy_seq (asn1_node tpm2key, tpm2key_authpolicy_t *authpol_seq);
+
+void
+grub_tpm2key_free_authpolicy_seq (tpm2key_authpolicy_t authpol_seq);
+
+#endif /* GRUB_TPM2_TPM2KEY_HEADER */
diff --git a/grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c b/grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c
new file mode 100644
index 000000000..bebe108a3
--- /dev/null
+++ b/grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c
@@ -0,0 +1,63 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 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/>.
+ */
+
+/*
+ * This file is generated by 'asn1Parser tpm2key.asn' and the '#include'
+ * headers are replaced with the ones in grub2.
+ * - 'grub/mm.h' for the definition of 'NULL'
+ * - 'libtasn1.h' for the definition of 'asn1_static_node'
+ */
+
+#include <grub/mm.h>
+#include <libtasn1.h>
+
+const asn1_static_node tpm2key_asn1_tab[] = {
+ { "TPM2KEY", 536875024, NULL },
+ { NULL, 1073741836, NULL },
+ { "TPMPolicy", 1610612741, NULL },
+ { "CommandCode", 1610620931, NULL },
+ { NULL, 2056, "0"},
+ { "CommandPolicy", 536879111, NULL },
+ { NULL, 2056, "1"},
+ { "TPMAuthPolicy", 1610612741, NULL },
+ { "Name", 1610637346, NULL },
+ { NULL, 2056, "0"},
+ { "Policy", 536879115, NULL },
+ { NULL, 1073743880, "1"},
+ { NULL, 2, "TPMPolicy"},
+ { "TPMKey", 536870917, NULL },
+ { "type", 1073741836, NULL },
+ { "emptyAuth", 1610637316, NULL },
+ { NULL, 2056, "0"},
+ { "policy", 1610637323, NULL },
+ { NULL, 1073743880, "1"},
+ { NULL, 2, "TPMPolicy"},
+ { "secret", 1610637319, NULL },
+ { NULL, 2056, "2"},
+ { "authPolicy", 1610637323, NULL },
+ { NULL, 1073743880, "3"},
+ { NULL, 2, "TPMAuthPolicy"},
+ { "description", 1610637346, NULL },
+ { NULL, 2056, "4"},
+ { "rsaParent", 1610637316, NULL },
+ { NULL, 2056, "5"},
+ { "parent", 1073741827, NULL },
+ { "pubkey", 1073741831, NULL },
+ { "privkey", 7, NULL },
+ { NULL, 0, NULL }
+};
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 23/33] cryptodisk: Support key protectors
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (21 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 22/33] key_protector: Add TPM2 Key Protector Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 24/33] util/grub-protect: Add new tool Gary Lin via Grub-devel
` (11 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Hernan Gatta <hegatta@linux.microsoft.com>
Add a new parameter to cryptomount to support the key protectors framework: -P.
The parameter is used to automatically retrieve a key from specified key
protectors. The parameter may be repeated to specify any number of key
protectors. These are tried in order until one provides a usable key for any
given disk.
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
Makefile.util.def | 1 +
grub-core/disk/cryptodisk.c | 243 ++++++++++++++++++++++++++----------
include/grub/cryptodisk.h | 16 +++
3 files changed, 196 insertions(+), 64 deletions(-)
diff --git a/Makefile.util.def b/Makefile.util.def
index fe70cf9bd..fb82f59a0 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -40,6 +40,7 @@ library = {
common = grub-core/disk/luks.c;
common = grub-core/disk/luks2.c;
common = grub-core/disk/geli.c;
+ common = grub-core/disk/key_protector.c;
common = grub-core/disk/cryptodisk.c;
common = grub-core/disk/AFSplitter.c;
common = grub-core/lib/pbkdf2.c;
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 5e1eb2743..6f7394942 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -27,6 +27,7 @@
#include <grub/file.h>
#include <grub/procfs.h>
#include <grub/partition.h>
+#include <grub/key_protector.h>
#ifdef GRUB_UTIL
#include <grub/emu/hostdisk.h>
@@ -45,7 +46,8 @@ enum
OPTION_KEYFILE,
OPTION_KEYFILE_OFFSET,
OPTION_KEYFILE_SIZE,
- OPTION_HEADER
+ OPTION_HEADER,
+ OPTION_PROTECTOR
};
static const struct grub_arg_option options[] =
@@ -59,6 +61,8 @@ static const struct grub_arg_option options[] =
{"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT},
{"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT},
{"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},
{0, 0, 0, 0, 0, 0}
};
@@ -1062,6 +1066,7 @@ grub_cryptodisk_scan_device_real (const char *name,
grub_err_t ret = GRUB_ERR_NONE;
grub_cryptodisk_t dev;
grub_cryptodisk_dev_t cr;
+ int i;
struct cryptodisk_read_hook_ctx read_hook_data = {0};
int askpass = 0;
char *part = NULL;
@@ -1114,79 +1119,151 @@ grub_cryptodisk_scan_device_real (const char *name,
goto error_no_close;
if (!dev)
continue;
+ break;
+ }
- if (cargs->key_len)
- {
- ret = cr->recover_key (source, dev, cargs);
- if (ret != GRUB_ERR_NONE)
- goto error;
- }
- else
- {
- /* Get the passphrase from the user, if no key data. */
- unsigned long tries = 3;
- const char *tries_env;
+ if (dev == NULL)
+ {
+ grub_error (GRUB_ERR_BAD_MODULE,
+ "no cryptodisk module can handle this device");
+ goto error_no_close;
+ }
- askpass = 1;
- cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
- if (cargs->key_data == NULL)
- goto error_no_close;
+ if (cargs->protectors)
+ {
+ for (i = 0; cargs->protectors[i]; i++)
+ {
+ if (cargs->key_cache[i].invalid)
+ continue;
- tries_env = grub_env_get ("cryptodisk_passphrase_tries");
- if (tries_env != NULL && tries_env[0] != '\0')
- {
- unsigned long tries_env_val;
- const char *p;
+ if (cargs->key_cache[i].key == NULL)
+ {
+ ret = grub_key_protector_recover_key (cargs->protectors[i],
+ &cargs->key_cache[i].key,
+ &cargs->key_cache[i].key_len);
+ if (ret != GRUB_ERR_NONE)
+ {
+ if (grub_errno)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ grub_dprintf ("cryptodisk",
+ "failed to recover a key from key protector "
+ "%s, will not try it again for any other "
+ "disks, if any, during this invocation of "
+ "cryptomount\n",
+ cargs->protectors[i]);
+
+ cargs->key_cache[i].invalid = 1;
+ continue;
+ }
+ }
- tries_env_val = grub_strtoul (tries_env, &p, 0);
- if (*p == '\0' && tries_env_val != ~0UL)
- tries = tries_env_val;
- else
- grub_printf_ (N_("Invalid cryptodisk_passphrase_tries value `%s'. Defaulting to %lu.\n"),
- tries_env,
- tries);
- }
+ cargs->key_data = cargs->key_cache[i].key;
+ cargs->key_len = cargs->key_cache[i].key_len;
- for (; tries > 0; tries--)
- {
- part = grub_partition_get_name (source->partition);
- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
- source->partition != NULL ? "," : "",
- part != NULL ? part : N_("UNKNOWN"),
- dev->uuid);
- grub_free (part);
-
- if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
- {
- grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret != GRUB_ERR_NONE)
+ {
+ part = grub_partition_get_name (source->partition);
+ grub_dprintf ("cryptodisk",
+ "recovered a key from key protector %s but it "
+ "failed to unlock %s%s%s (%s)\n",
+ cargs->protectors[i], source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
+ grub_free (part);
+ continue;
+ }
+ else
+ {
+ ret = grub_cryptodisk_insert (dev, name, source);
+ if (ret != GRUB_ERR_NONE)
goto error;
- }
- cargs->key_len = grub_strlen ((char *) cargs->key_data);
+ goto cleanup;
+ }
+ }
+
+ part = grub_partition_get_name (source->partition);
+ grub_error (GRUB_ERR_ACCESS_DENIED,
+ N_("no key protector provided a usable key for %s%s%s (%s)"),
+ source->name, source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
+ grub_free (part);
+ goto error;
+ }
+
+ if (cargs->key_len)
+ {
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
+ }
+ else
+ {
+ /* Get the passphrase from the user, if no key data. */
+ unsigned long tries = 3;
+ const char *tries_env;
- ret = cr->recover_key (source, dev, cargs);
- if (ret == GRUB_ERR_NONE)
- break;
- if (ret != GRUB_ERR_ACCESS_DENIED || tries == 1)
+ askpass = 1;
+ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ if (cargs->key_data == NULL)
+ goto error_no_close;
+
+ tries_env = grub_env_get ("cryptodisk_passphrase_tries");
+ if (tries_env != NULL && tries_env[0] != '\0')
+ {
+ unsigned long tries_env_val;
+ const char *p;
+
+ tries_env_val = grub_strtoul (tries_env, &p, 0);
+ if (*p == '\0' && tries_env_val != ~0UL)
+ tries = tries_env_val;
+ else
+ grub_printf_ (N_("Invalid cryptodisk_passphrase_tries value `%s'. Defaulting to %lu.\n"),
+ tries_env,
+ tries);
+ }
+
+ for (; tries > 0; tries--)
+ {
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"),
+ dev->uuid);
+ grub_free (part);
+
+ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
goto error;
- grub_puts_ (N_("Invalid passphrase."));
-
- /*
- * Since recover_key() calls a function that returns grub_errno,
- * a leftover error value from a previously rejected passphrase
- * will trigger a phantom failure. We therefore clear it before
- * trying a new passphrase.
- */
- grub_errno = GRUB_ERR_NONE;
- }
- }
+ }
+ cargs->key_len = grub_strlen ((char *) cargs->key_data);
- ret = grub_cryptodisk_insert (dev, name, source);
- if (ret != GRUB_ERR_NONE)
- goto error;
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret == GRUB_ERR_NONE)
+ break;
+ if (ret != GRUB_ERR_ACCESS_DENIED || tries == 1)
+ goto error;
+ grub_puts_ (N_("Invalid passphrase."));
+
+ /*
+ * Since recover_key() calls a function that returns grub_errno,
+ * a leftover error value from a previously rejected passphrase
+ * will trigger a phantom failure. We therefore clear it before
+ * trying a new passphrase.
+ */
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
+
+ ret = grub_cryptodisk_insert (dev, name, source);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
- goto cleanup;
- }
- grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
goto cleanup;
error:
@@ -1298,6 +1375,20 @@ grub_cryptodisk_scan_device (const char *name,
return ret;
}
+static void
+grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs)
+{
+ int i;
+
+ if (cargs->key_cache == NULL || cargs->protectors == NULL)
+ return;
+
+ for (i = 0; cargs->protectors[i]; i++)
+ grub_free (cargs->key_cache[i].key);
+
+ grub_free (cargs->key_cache);
+}
+
static grub_err_t
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
@@ -1310,6 +1401,14 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
if (grub_cryptodisk_list == NULL)
return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded");
+ if (state[OPTION_PASSWORD].set && state[OPTION_PROTECTOR].set) /* password and key protector */
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a password and a key protector cannot both be set");
+
+ if (state[OPTION_KEYFILE].set && state[OPTION_PROTECTOR].set) /* key file and key protector */
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a key file and a key protector cannot both be set");
+
if (state[OPTION_PASSWORD].set) /* password */
{
cargs.key_data = (grub_uint8_t *) state[OPTION_PASSWORD].arg;
@@ -1402,6 +1501,15 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return grub_errno;
}
+ if (state[OPTION_PROTECTOR].set) /* key protector(s) */
+ {
+ cargs.key_cache = grub_zalloc (state[OPTION_PROTECTOR].set * sizeof (*cargs.key_cache));
+ if (cargs.key_cache == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "no memory for key protector key cache");
+ cargs.protectors = state[OPTION_PROTECTOR].args;
+ }
+
if (state[OPTION_UUID].set) /* uuid */
{
int found_uuid;
@@ -1410,6 +1518,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
dev = grub_cryptodisk_get_by_uuid (args[0]);
if (dev)
{
+ grub_cryptodisk_clear_key_cache (&cargs);
grub_dprintf ("cryptodisk",
"already mounted as crypto%lu\n", dev->id);
return GRUB_ERR_NONE;
@@ -1418,6 +1527,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
cargs.check_boot = state[OPTION_BOOT].set;
cargs.search_uuid = args[0];
found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
+ grub_cryptodisk_clear_key_cache (&cargs);
if (found_uuid)
return GRUB_ERR_NONE;
@@ -1437,6 +1547,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
cargs.check_boot = state[OPTION_BOOT].set;
grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
+ grub_cryptodisk_clear_key_cache (&cargs);
return GRUB_ERR_NONE;
}
else
@@ -1460,6 +1571,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
disk = grub_disk_open (diskname);
if (!disk)
{
+ grub_cryptodisk_clear_key_cache (&cargs);
if (disklast)
*disklast = ')';
return grub_errno;
@@ -1470,12 +1582,14 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id);
grub_disk_close (disk);
+ grub_cryptodisk_clear_key_cache (&cargs);
if (disklast)
*disklast = ')';
return GRUB_ERR_NONE;
}
dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs);
+ grub_cryptodisk_clear_key_cache (&cargs);
grub_disk_close (disk);
if (disklast)
@@ -1629,6 +1743,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 ...]]"
" <SOURCE|-u UUID|-a|-b>"),
N_("Mount a crypto device."), options);
grub_procfs_register ("luks_script", &luks_script);
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index d94df68b6..59b461e7a 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -70,6 +70,18 @@ typedef gcry_err_code_t
(*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev,
grub_uint64_t zoneno);
+struct grub_cryptomount_cached_key
+{
+ grub_uint8_t *key;
+ grub_size_t key_len;
+
+ /*
+ * The key protector associated with this cache entry failed, so avoid it
+ * even if the cached entry (an instance of this structure) is empty.
+ */
+ bool invalid;
+};
+
struct grub_cryptomount_args
{
/* scan: Flag to indicate that only bootable volumes should be decrypted */
@@ -81,6 +93,10 @@ struct grub_cryptomount_args
/* recover_key: Length of key_data */
grub_size_t key_len;
grub_file_t hdr_file;
+ /* recover_key: Names of the key protectors to use (NULL-terminated) */
+ char **protectors;
+ /* recover_key: Key cache to avoid invoking the same key protector twice */
+ struct grub_cryptomount_cached_key *key_cache;
};
typedef struct grub_cryptomount_args *grub_cryptomount_args_t;
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 24/33] util/grub-protect: Add new tool
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (22 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 23/33] cryptodisk: Support key protectors Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-16 16:04 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 25/33] tpm2_key_protector: Support authorized policy Gary Lin via Grub-devel
` (10 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Hernan Gatta <hegatta@linux.microsoft.com>
To utilize the key protectors framework, there must be a way to protect
full-disk encryption keys in the first place. The grub-protect tool
includes support for the TPM2 key protector but other protectors that
require setup ahead of time can be supported in the future.
For the TPM2 key protector, the intended flow is for a user to have a
LUKS 1 or LUKS 2-protected fully-encrypted disk. The user then creates a
new LUKS key file, say by reading /dev/urandom into a file, and creates
a new LUKS key slot for this key. Then, the user invokes the grub-protect
tool to seal this key file to a set of PCRs using the system's TPM 2.0.
The resulting sealed key file is stored in an unencrypted partition such
as the EFI System Partition (ESP) so that GRUB may read it. The user also
has to ensure the cryptomount command is included in GRUB's boot script
and that it carries the requisite key protector (-P) parameter.
Sample usage:
$ dd if=/dev/urandom of=luks-key bs=1 count=32
$ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2 --hash=sha512
To seal the key with TPM 2.0 Key File (recommended):
$ sudo grub-protect --action=add \
--protector=tpm2 \
--tpm2-pcrs=0,2,4,7,9 \
--tpm2key \
--tpm2-keyfile=luks-key \
--tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm
Or, to seal the key with the raw sealed key:
$ sudo grub-protect --action=add \
--protector=tpm2 \
--tpm2-pcrs=0,2,4,7,9 \
--tpm2-keyfile=luks-key \
--tpm2-outfile=/boot/efi/boot/grub2/sealed.key
Then, in the boot script, for TPM 2.0 Key File:
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
cryptomount -u <SDB1_UUID> -P tpm2
Or, for the raw sealed key:
tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.key --pcrs=0,2,4,7,9
cryptomount -u <SDB1_UUID> -P tpm2
The benefit of using TPM 2.0 Key File is that the PCR set is already
written in the key file, so there is no need to specify PCRs when
invoking tpm2_key_protector_init.
Cc: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
---
.gitignore | 2 +
Makefile.util.def | 26 +
configure.ac | 30 +
docs/man/grub-protect.h2m | 4 +
util/grub-protect.c | 1394 +++++++++++++++++++++++++++++++++++++
5 files changed, 1456 insertions(+)
create mode 100644 docs/man/grub-protect.h2m
create mode 100644 util/grub-protect.c
diff --git a/.gitignore b/.gitignore
index 4c1f91db8..2105d87c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -169,6 +169,8 @@ widthspec.bin
/grub-ofpathname.exe
/grub-probe
/grub-probe.exe
+/grub-protect
+/grub-protect.exe
/grub-reboot
/grub-render-label
/grub-render-label.exe
diff --git a/Makefile.util.def b/Makefile.util.def
index fb82f59a0..074c0aff7 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -208,6 +208,32 @@ program = {
ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
};
+program = {
+ name = grub-protect;
+ mansection = 1;
+
+ common = grub-core/kern/emu/argp_common.c;
+ common = grub-core/osdep/init.c;
+ common = grub-core/lib/tss2/buffer.c;
+ common = grub-core/lib/tss2/tss2_mu.c;
+ common = grub-core/lib/tss2/tpm2_cmd.c;
+ common = grub-core/commands/tpm2_key_protector/args.c;
+ common = grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c;
+ common = util/grub-protect.c;
+ common = util/probe.c;
+
+ 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 = grub-core/lib/gnulib/libgnu.a;
+ ldadd = '$(LIBTASN1)';
+ ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+
+ condition = COND_GRUB_PROTECT;
+};
+
program = {
name = grub-mkrelpath;
mansection = 1;
diff --git a/configure.ac b/configure.ac
index 458b8382b..ad1e7bea5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,6 +76,7 @@ grub_TRANSFORM([grub-mkpasswd-pbkdf2])
grub_TRANSFORM([grub-mkrelpath])
grub_TRANSFORM([grub-mkrescue])
grub_TRANSFORM([grub-probe])
+grub_TRANSFORM([grub-protect])
grub_TRANSFORM([grub-reboot])
grub_TRANSFORM([grub-script-check])
grub_TRANSFORM([grub-set-default])
@@ -2068,6 +2069,29 @@ fi
AC_SUBST([LIBZFS])
AC_SUBST([LIBNVPAIR])
+AC_ARG_ENABLE([grub-protect],
+ [AS_HELP_STRING([--enable-grub-protect],
+ [build and install the `grub-protect' utility (default=guessed)])])
+if test x"$enable_grub_protect" = xno ; then
+ grub_protect_excuse="explicitly disabled"
+fi
+
+LIBTASN1=
+if test x"$grub_protect_excuse" = x ; then
+ AC_CHECK_LIB([tasn1], [asn1_write_value], [LIBTASN1="-ltasn1"], [grub_protect_excuse="need libtasn1 library"])
+fi
+AC_SUBST([LIBTASN1])
+
+if test x"$enable_grub_protect" = xyes && test x"$grub_protect_excuse" != x ; then
+ AC_MSG_ERROR([grub-protect was explicitly requested but can't be compiled ($grub_protect_excuse)])
+fi
+if test x"$grub_protect_excuse" = x ; then
+enable_grub_protect=yes
+else
+enable_grub_protect=no
+fi
+AC_SUBST([enable_grub_protect])
+
LIBS=""
AC_SUBST([FONT_SOURCE])
@@ -2184,6 +2208,7 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes])
AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes])
AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes])
AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes])
+AM_CONDITIONAL([COND_GRUB_PROTECT], [test x$enable_grub_protect = xyes])
AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x])
if test x$FONT_SOURCE != x ; then
HAVE_FONT_SOURCE=1
@@ -2311,6 +2336,11 @@ echo grub-mount: Yes
else
echo grub-mount: No "($grub_mount_excuse)"
fi
+if [ x"$grub_protect_excuse" = x ]; then
+echo grub-protect: Yes
+else
+echo grub-protect: No "($grub_protect_excuse)"
+fi
if [ x"$starfield_excuse" = x ]; then
echo starfield theme: Yes
echo With DejaVuSans font from $DJVU_FONT_SOURCE
diff --git a/docs/man/grub-protect.h2m b/docs/man/grub-protect.h2m
new file mode 100644
index 000000000..ecf1c9eab
--- /dev/null
+++ b/docs/man/grub-protect.h2m
@@ -0,0 +1,4 @@
+[NAME]
+grub-protect \- protect a disk key with a key protector
+[DESCRIPTION]
+grub-protect helps to protect a disk encryption key with a specified key protector.
diff --git a/util/grub-protect.c b/util/grub-protect.c
new file mode 100644
index 000000000..fb4ea4079
--- /dev/null
+++ b/util/grub-protect.c
@@ -0,0 +1,1394 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2023 SUSE LLC
+ * Copyright (C) 2024 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 <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libtasn1.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/misc.h>
+
+#include <grub/util/misc.h>
+
+#include <tss2_buffer.h>
+#include <tss2_mu.h>
+#include <tcg2.h>
+#include <tpm2_args.h>
+#include <tpm2.h>
+
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#pragma GCC diagnostic ignored "-Wmissing-declarations"
+#include <argp.h>
+#pragma GCC diagnostic error "-Wmissing-prototypes"
+#pragma GCC diagnostic error "-Wmissing-declarations"
+
+#include "progname.h"
+
+/* Unprintable option keys for argp */
+typedef enum grub_protect_opt
+{
+ /* General */
+ GRUB_PROTECT_OPT_ACTION = 'a',
+ GRUB_PROTECT_OPT_PROTECTOR = 'p',
+ /* TPM2 */
+ GRUB_PROTECT_OPT_TPM2_DEVICE = 0x100,
+ GRUB_PROTECT_OPT_TPM2_PCRS,
+ GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
+ GRUB_PROTECT_OPT_TPM2_BANK,
+ GRUB_PROTECT_OPT_TPM2_SRK,
+ GRUB_PROTECT_OPT_TPM2_KEYFILE,
+ GRUB_PROTECT_OPT_TPM2_OUTFILE,
+ GRUB_PROTECT_OPT_TPM2_EVICT,
+ GRUB_PROTECT_OPT_TPM2_TPM2KEY
+} grub_protect_opt;
+
+/* Option flags to keep track of specified arguments */
+typedef enum grub_protect_arg
+{
+ /* General */
+ GRUB_PROTECT_ARG_ACTION = 1 << 0,
+ GRUB_PROTECT_ARG_PROTECTOR = 1 << 1,
+ /* TPM2 */
+ GRUB_PROTECT_ARG_TPM2_DEVICE = 1 << 2,
+ GRUB_PROTECT_ARG_TPM2_PCRS = 1 << 3,
+ GRUB_PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4,
+ GRUB_PROTECT_ARG_TPM2_BANK = 1 << 5,
+ GRUB_PROTECT_ARG_TPM2_SRK = 1 << 6,
+ GRUB_PROTECT_ARG_TPM2_KEYFILE = 1 << 7,
+ GRUB_PROTECT_ARG_TPM2_OUTFILE = 1 << 8,
+ GRUB_PROTECT_ARG_TPM2_EVICT = 1 << 9,
+ GRUB_PROTECT_ARG_TPM2_TPM2KEY = 1 << 10
+} grub_protect_arg_t;
+
+typedef enum grub_protect_protector
+{
+ GRUB_PROTECT_TYPE_ERROR,
+ GRUB_PROTECT_TYPE_TPM2
+} grub_protect_protector_t;
+
+typedef enum grub_protect_action
+{
+ GRUB_PROTECT_ACTION_ERROR,
+ GRUB_PROTECT_ACTION_ADD,
+ GRUB_PROTECT_ACTION_REMOVE
+} grub_protect_action_t;
+
+struct grub_protect_args
+{
+ grub_protect_arg_t args;
+ grub_protect_action_t action;
+ grub_protect_protector_t protector;
+
+ const char *tpm2_device;
+ grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS];
+ grub_uint8_t tpm2_pcr_count;
+ grub_srk_type_t srk_type;
+ TPM_ALG_ID_t tpm2_bank;
+ TPM_HANDLE_t tpm2_srk;
+ const char *tpm2_keyfile;
+ const char *tpm2_outfile;
+ int tpm2_evict;
+ int tpm2_tpm2key;
+};
+
+static struct argp_option grub_protect_options[] =
+ {
+ /* Top-level options */
+ {
+ .name = "action",
+ .key = 'a',
+ .arg = "add|remove",
+ .flags = 0,
+ .doc =
+ N_("Add or remove a key protector to or from a key."),
+ .group = 0
+ },
+ {
+ .name = "protector",
+ .key = 'p',
+ .arg = "tpm2",
+ .flags = 0,
+ .doc =
+ N_("Set key protector to use (only tpm2 is currently supported)."),
+ .group = 0
+ },
+ /* TPM2 key protector options */
+ {
+ .name = "tpm2-device",
+ .key = GRUB_PROTECT_OPT_TPM2_DEVICE,
+ .arg = "FILE",
+ .flags = 0,
+ .doc =
+ N_("Set the path to the TPM2 device. (default: /dev/tpm0)"),
+ .group = 0
+ },
+ {
+ .name = "tpm2-pcrs",
+ .key = GRUB_PROTECT_OPT_TPM2_PCRS,
+ .arg = "0[,1]...",
+ .flags = 0,
+ .doc =
+ N_("Set a comma-separated list of PCRs used to authorize key release "
+ "e.g., '7,11'. Please be aware that PCR 0~7 are used by the "
+ "firmware and the measurement result may change after a "
+ "firmware update (for baremetal systems) or a package "
+ "(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to "
+ "the failure of key unsealing. (default: 7)"),
+ .group = 0
+ },
+ {
+ .name = "tpm2-bank",
+ .key = GRUB_PROTECT_OPT_TPM2_BANK,
+ .arg = "ALG",
+ .flags = 0,
+ .doc =
+ N_("Set the bank of PCRs used to authorize key release: "
+ "SHA1, SHA256, SHA384, or SHA512. (default: SHA256)"),
+ .group = 0
+ },
+ {
+ .name = "tpm2-keyfile",
+ .key = GRUB_PROTECT_OPT_TPM2_KEYFILE,
+ .arg = "FILE",
+ .flags = 0,
+ .doc =
+ N_("Set the path to a file that contains the cleartext key to protect."),
+ .group = 0
+ },
+ {
+ .name = "tpm2-outfile",
+ .key = GRUB_PROTECT_OPT_TPM2_OUTFILE,
+ .arg = "FILE",
+ .flags = 0,
+ .doc =
+ N_("Set the path to the file that will contain the key after sealing "
+ "(must be accessible to GRUB during boot)."),
+ .group = 0
+ },
+ {
+ .name = "tpm2-srk",
+ .key = GRUB_PROTECT_OPT_TPM2_SRK,
+ .arg = "NUM",
+ .flags = 0,
+ .doc =
+ N_("Set the SRK handle if the SRK is to be made persistent."),
+ .group = 0
+ },
+ {
+ .name = "tpm2-asymmetric",
+ .key = GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
+ .arg = "TYPE",
+ .flags = 0,
+ .doc =
+ N_("Set the type of SRK: RSA (RSA2048) and ECC (ECC_NIST_P256)."
+ "(default: ECC)"),
+ .group = 0
+ },
+ {
+ .name = "tpm2-evict",
+ .key = GRUB_PROTECT_OPT_TPM2_EVICT,
+ .arg = NULL,
+ .flags = 0,
+ .doc =
+ N_("Evict a previously persisted SRK from the TPM, if any."),
+ .group = 0
+ },
+ {
+ .name = "tpm2key",
+ .key = GRUB_PROTECT_OPT_TPM2_TPM2KEY,
+ .arg = NULL,
+ .flags = 0,
+ .doc =
+ N_("Use TPM 2.0 Key File format instead of the raw format."),
+ .group = 0
+ },
+ /* End of list */
+ { 0, 0, 0, 0, 0, 0 }
+ };
+
+static int protector_tpm2_fd = -1;
+
+static grub_err_t
+protect_read_file (const char *filepath, void **buffer, size_t *buffer_size)
+{
+ grub_err_t err;
+ FILE *f;
+ long len;
+ void *buf;
+
+ f = fopen (filepath, "rb");
+ if (f == NULL)
+ return GRUB_ERR_FILE_NOT_FOUND;
+
+ if (fseek (f, 0, SEEK_END))
+ {
+ err = GRUB_ERR_FILE_READ_ERROR;
+ goto exit1;
+ }
+
+ len = ftell (f);
+ if (len <= 0)
+ {
+ err = GRUB_ERR_FILE_READ_ERROR;
+ goto exit1;
+ }
+
+ rewind (f);
+
+ buf = grub_malloc (len);
+ if (buf == NULL)
+ {
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ goto exit1;
+ }
+
+ if (fread (buf, len, 1, f) != 1)
+ {
+ err = GRUB_ERR_FILE_READ_ERROR;
+ goto exit2;
+ }
+
+ *buffer = buf;
+ *buffer_size = len;
+
+ buf = NULL;
+ err = GRUB_ERR_NONE;
+
+ exit2:
+ grub_free (buf);
+
+ exit1:
+ fclose (f);
+
+ return err;
+}
+
+static grub_err_t
+protect_write_file (const char *filepath, void *buffer, size_t buffer_size)
+{
+ grub_err_t err;
+ FILE *f;
+
+ f = fopen (filepath, "wb");
+ if (f == NULL)
+ return GRUB_ERR_FILE_NOT_FOUND;
+
+ if (fwrite (buffer, buffer_size, 1, f) != 1)
+ {
+ err = GRUB_ERR_WRITE_ERROR;
+ goto exit1;
+ }
+
+ err = GRUB_ERR_NONE;
+
+ exit1:
+ fclose (f);
+
+ return err;
+}
+
+grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size)
+{
+ if (size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *size = GRUB_TPM2_BUFFER_CAPACITY;
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
+ grub_size_t output_size, grub_uint8_t *output)
+{
+ static const grub_size_t header_size = sizeof (grub_uint16_t) +
+ (2 * sizeof(grub_uint32_t));
+
+ if (write (protector_tpm2_fd, input, input_size) != input_size)
+ return GRUB_ERR_BAD_DEVICE;
+
+ if (read (protector_tpm2_fd, output, output_size) < header_size)
+ return GRUB_ERR_BAD_DEVICE;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+protect_tpm2_open_device (const char *dev_node)
+{
+ if (protector_tpm2_fd != -1)
+ return GRUB_ERR_NONE;
+
+ protector_tpm2_fd = open (dev_node, O_RDWR);
+ if (protector_tpm2_fd == -1)
+ {
+ fprintf (stderr, "Could not open TPM device (%s).\n", strerror (errno));
+ return GRUB_ERR_FILE_NOT_FOUND;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+protect_tpm2_close_device (void)
+{
+ int err;
+
+ if (protector_tpm2_fd == -1)
+ return GRUB_ERR_NONE;
+
+ err = close (protector_tpm2_fd);
+ if (err != GRUB_ERR_NONE)
+ {
+ fprintf (stderr, "Could not close TPM device (Error: %u).\n", errno);
+ return GRUB_ERR_IO;
+ }
+
+ protector_tpm2_fd = -1;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+protect_tpm2_get_policy_digest (struct grub_protect_args *args, TPM2B_DIGEST_t *digest)
+{
+ TPM_RC_t rc;
+ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
+ .hash = args->tpm2_bank,
+ .sizeOfSelect = 3,
+ .pcrSelect = { 0 }
+ },
+ }
+ };
+ TPML_PCR_SELECTION_t pcr_sel_out = { 0 };
+ TPML_DIGEST_t pcr_values = { 0 };
+ TPM2B_DIGEST_t pcr_digest = { 0 };
+ grub_size_t pcr_digest_len;
+ TPM2B_MAX_BUFFER_t pcr_concat = { 0 };
+ grub_size_t pcr_concat_len;
+ grub_uint8_t *pcr_cursor;
+ TPM2B_NONCE_t nonce = { 0 };
+ TPM2B_ENCRYPTED_SECRET_t salt = { 0 };
+ TPMT_SYM_DEF_t symmetric = { 0 };
+ TPMI_SH_AUTH_SESSION_t session = 0;
+ TPM2B_DIGEST_t policy_digest = { 0 };
+ grub_uint8_t i;
+ grub_err_t err;
+
+ /* PCR Read */
+ for (i = 0; i < args->tpm2_pcr_count; i++)
+ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], args->tpm2_pcrs[i]);
+
+ rc = grub_tpm2_pcr_read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to read PCRs (TPM2_PCR_Read: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ if ((pcr_sel_out.count != pcr_sel.count) ||
+ (pcr_sel.pcrSelections[0].sizeOfSelect !=
+ pcr_sel_out.pcrSelections[0].sizeOfSelect))
+ {
+ fprintf (stderr, "Could not read all the specified PCRs.\n");
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Compute PCR Digest */
+ switch (args->tpm2_bank)
+ {
+ case TPM_ALG_SHA1:
+ pcr_digest_len = TPM_SHA1_DIGEST_SIZE;
+ break;
+ case TPM_ALG_SHA256:
+ pcr_digest_len = TPM_SHA256_DIGEST_SIZE;
+ break;
+ case TPM_ALG_SHA384:
+ pcr_digest_len = TPM_SHA384_DIGEST_SIZE;
+ break;
+ case TPM_ALG_SHA512:
+ pcr_digest_len = TPM_SHA512_DIGEST_SIZE;
+ break;
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count;
+ if (pcr_concat_len > TPM_MAX_DIGEST_BUFFER)
+ {
+ fprintf (stderr, "PCR concatenation buffer not enough.\n");
+ return GRUB_ERR_OUT_OF_RANGE;
+ }
+
+ pcr_cursor = pcr_concat.buffer;
+ for (i = 0; i < args->tpm2_pcr_count; i++)
+ {
+ if (pcr_values.digests[i].size != pcr_digest_len)
+ {
+ fprintf (stderr,
+ "Bad PCR value size: expected %" PRIuGRUB_SIZE " bytes but got %u bytes.\n",
+ pcr_digest_len, pcr_values.digests[i].size);
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ grub_memcpy (pcr_cursor, pcr_values.digests[i].buffer, pcr_digest_len);
+ pcr_cursor += pcr_digest_len;
+ }
+ pcr_concat.size = pcr_concat_len;
+
+ rc = grub_tpm2_hash (NULL, &pcr_concat, args->tpm2_bank, TPM_RH_NULL, &pcr_digest, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to generate PCR digest (TPM2_Hash: 0x%x)\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Start Trial Session */
+ nonce.size = TPM_SHA256_DIGEST_SIZE;
+ symmetric.algorithm = TPM_ALG_NULL;
+
+ rc = grub_tpm2_startauthsession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonce, &salt,
+ TPM_SE_TRIAL, &symmetric, TPM_ALG_SHA256,
+ &session, NULL, 0);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to start trial policy session (TPM2_StartAuthSession: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* PCR Policy */
+ rc = grub_tpm2_policypcr (session, NULL, &pcr_digest, &pcr_sel, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to submit PCR policy (TPM2_PolicyPCR: 0x%x).\n", rc);
+ err = GRUB_ERR_BAD_DEVICE;
+ goto error;
+ }
+
+ /* Retrieve Policy Digest */
+ rc = grub_tpm2_policygetdigest (session, NULL, &policy_digest, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to get policy digest (TPM2_PolicyGetDigest: 0x%x).\n", rc);
+ err = GRUB_ERR_BAD_DEVICE;
+ goto error;
+ }
+
+ /* Epilogue */
+ *digest = policy_digest;
+ err = GRUB_ERR_NONE;
+
+ error:
+ grub_tpm2_flushcontext (session);
+
+ return err;
+}
+
+static grub_err_t
+protect_tpm2_get_srk (struct grub_protect_args *args, TPM_HANDLE_t *srk)
+{
+ TPM_RC_t rc;
+ TPM2B_PUBLIC_t public;
+ TPMS_AUTH_COMMAND_t authCommand = { 0 };
+ TPM2B_SENSITIVE_CREATE_t inSensitive = { 0 };
+ TPM2B_PUBLIC_t inPublic = { 0 };
+ TPM2B_DATA_t outsideInfo = { 0 };
+ TPML_PCR_SELECTION_t creationPcr = { 0 };
+ TPM2B_PUBLIC_t outPublic = { 0 };
+ TPM2B_CREATION_DATA_t creationData = { 0 };
+ TPM2B_DIGEST_t creationHash = { 0 };
+ TPMT_TK_CREATION_t creationTicket = { 0 };
+ TPM2B_NAME_t srkName = { 0 };
+ TPM_HANDLE_t srkHandle;
+
+ if (args->tpm2_srk != 0)
+ {
+ /* Find SRK */
+ rc = grub_tpm2_readpublic (args->tpm2_srk, NULL, &public);
+ if (rc == TPM_RC_SUCCESS)
+ {
+ printf ("Read SRK from 0x%x\n", args->tpm2_srk);
+ *srk = args->tpm2_srk;
+ return GRUB_ERR_NONE;
+ }
+
+ /* The handle exists but its public area could not be read. */
+ if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE)
+ {
+ fprintf (stderr, "Failed to retrieve SRK from 0x%x (TPM2_ReadPublic: 0x%x).\n", args->tpm2_srk, rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+ }
+
+ /* Create SRK */
+ authCommand.sessionHandle = TPM_RS_PW;
+ inPublic.publicArea.type = args->srk_type.type;
+ inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
+ inPublic.publicArea.objectAttributes.restricted = 1;
+ inPublic.publicArea.objectAttributes.userWithAuth = 1;
+ inPublic.publicArea.objectAttributes.decrypt = 1;
+ inPublic.publicArea.objectAttributes.fixedTPM = 1;
+ inPublic.publicArea.objectAttributes.fixedParent = 1;
+ inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1;
+ inPublic.publicArea.objectAttributes.noDA = 1;
+
+ switch (args->srk_type.type)
+ {
+ case TPM_ALG_RSA:
+ inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_AES;
+ inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
+ inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = TPM_ALG_CFB;
+ inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
+ inPublic.publicArea.parameters.rsaDetail.keyBits = args->srk_type.detail.rsa_bits;
+ inPublic.publicArea.parameters.rsaDetail.exponent = 0;
+ break;
+
+ case TPM_ALG_ECC:
+ inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
+ inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
+ inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
+ inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
+ inPublic.publicArea.parameters.eccDetail.curveID = args->srk_type.detail.ecc_curve;
+ inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+ break;
+
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ rc = grub_tpm2_createprimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic,
+ &outsideInfo, &creationPcr, &srkHandle, &outPublic,
+ &creationData, &creationHash, &creationTicket,
+ &srkName, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to create SRK (TPM2_CreatePrimary: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Persist SRK */
+ if (args->tpm2_srk != 0)
+ {
+ rc = grub_tpm2_evictcontrol (TPM_RH_OWNER, srkHandle, &authCommand, args->tpm2_srk, NULL);
+ if (rc == TPM_RC_SUCCESS)
+ {
+ grub_tpm2_flushcontext (srkHandle);
+ srkHandle = args->tpm2_srk;
+ }
+ else
+ fprintf (stderr,
+ "Warning: Failed to persist SRK (0x%x) (TPM2_EvictControl: 0x%x).\n"
+ "Continuing anyway...\n", args->tpm2_srk, rc);
+ }
+
+ /* Epilogue */
+ *srk = srkHandle;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+protect_tpm2_seal (TPM2B_DIGEST_t *policyDigest, TPM_HANDLE_t srk,
+ grub_uint8_t *clearText, grub_size_t clearTextLength,
+ tpm2_sealed_key_t *sealed_key)
+{
+ TPM_RC_t rc;
+ TPMS_AUTH_COMMAND_t authCommand = { 0 };
+ TPM2B_SENSITIVE_CREATE_t inSensitive = { 0 };
+ TPM2B_PUBLIC_t inPublic = { 0 };
+ TPM2B_DATA_t outsideInfo = { 0 };
+ TPML_PCR_SELECTION_t pcr_sel = { 0 };
+ TPM2B_PRIVATE_t outPrivate = { 0 };
+ TPM2B_PUBLIC_t outPublic = { 0 };
+
+ /* Seal Data */
+ authCommand.sessionHandle = TPM_RS_PW;
+
+ inSensitive.sensitive.data.size = clearTextLength;
+ memcpy(inSensitive.sensitive.data.buffer, clearText, clearTextLength);
+
+ inPublic.publicArea.type = TPM_ALG_KEYEDHASH;
+ inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
+ inPublic.publicArea.parameters.keyedHashDetail.scheme.scheme = TPM_ALG_NULL;
+ inPublic.publicArea.authPolicy = *policyDigest;
+
+ rc = grub_tpm2_create (srk, &authCommand, &inSensitive, &inPublic, &outsideInfo,
+ &pcr_sel, &outPrivate, &outPublic, NULL, NULL, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to seal key (TPM2_Create: 0x%x).\n", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Epilogue */
+ sealed_key->public = outPublic;
+ sealed_key->private = outPrivate;
+
+ return GRUB_ERR_NONE;
+}
+
+extern asn1_static_node tpm2key_asn1_tab[];
+
+static grub_err_t
+protect_tpm2_export_tpm2key (const struct grub_protect_args *args,
+ tpm2_sealed_key_t *sealed_key)
+{
+ const char *sealed_key_oid = "2.23.133.10.1.5";
+ asn1_node asn1_def = NULL;
+ asn1_node tpm2key = NULL;
+ grub_uint32_t parent;
+ grub_uint32_t cmd_code;
+ struct grub_tpm2_buffer pol_buf;
+ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
+ .hash = args->tpm2_bank,
+ .sizeOfSelect = 3,
+ .pcrSelect = { 0 }
+ },
+ }
+ };
+ struct grub_tpm2_buffer pub_buf;
+ struct grub_tpm2_buffer priv_buf;
+ void *der_buf = NULL;
+ int der_buf_size = 0;
+ int i;
+ int ret;
+ grub_err_t err;
+
+ for (i = 0; i < args->tpm2_pcr_count; i++)
+ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], args->tpm2_pcrs[i]);
+
+ /*
+ * Prepare the parameters for TPM_CC_PolicyPCR:
+ * empty pcrDigest and the user selected PCRs
+ */
+ grub_tpm2_buffer_init (&pol_buf);
+ grub_tpm2_buffer_pack_u16 (&pol_buf, 0);
+ grub_Tss2_MU_TPML_PCR_SELECTION_Marshal (&pol_buf, &pcr_sel);
+
+ grub_tpm2_buffer_init (&pub_buf);
+ grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&pub_buf, &sealed_key->public);
+ grub_tpm2_buffer_init (&priv_buf);
+ grub_Tss2_MU_TPM2B_Marshal (&priv_buf, sealed_key->private.size,
+ sealed_key->private.buffer);
+ if (pub_buf.error != 0 || priv_buf.error != 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ ret = asn1_array2tree (tpm2key_asn1_tab, &asn1_def, NULL);
+ if (ret != ASN1_SUCCESS)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ ret = asn1_create_element (asn1_def, "TPM2KEY.TPMKey" , &tpm2key);
+ if (ret != ASN1_SUCCESS)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ /* Set 'type' to "sealed key" */
+ ret = asn1_write_value (tpm2key, "type", sealed_key_oid, 1);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'type': 0x%u\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Set 'emptyAuth' to TRUE */
+ ret = asn1_write_value (tpm2key, "emptyAuth", "TRUE", 1);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'emptyAuth': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Set 'policy' */
+ ret = asn1_write_value (tpm2key, "policy", "NEW", 1);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'policy': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+ cmd_code = grub_cpu_to_be32 (TPM_CC_PolicyPCR);
+ ret = asn1_write_value (tpm2key, "policy.?LAST.CommandCode", &cmd_code,
+ sizeof (cmd_code));
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'policy CommandCode': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+ ret = asn1_write_value (tpm2key, "policy.?LAST.CommandPolicy", &pol_buf.data,
+ pol_buf.size);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'policy CommandPolicy': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Remove 'secret' */
+ ret = asn1_write_value (tpm2key, "secret", NULL, 0);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to remove 'secret': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Remove 'authPolicy' */
+ ret = asn1_write_value (tpm2key, "authPolicy", NULL, 0);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to remove 'authPolicy': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Remove 'description' */
+ ret = asn1_write_value (tpm2key, "description", NULL, 0);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to remove 'description': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /*
+ * Use the SRK handle as the parent handle if specified
+ * Otherwise, Use TPM_RH_OWNER as the default parent handle
+ */
+ if (args->tpm2_srk != 0)
+ parent = grub_cpu_to_be32 (args->tpm2_srk);
+ else
+ parent = grub_cpu_to_be32 (TPM_RH_OWNER);
+ ret = asn1_write_value (tpm2key, "parent", &parent, sizeof (parent));
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'parent': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /*
+ * Set 'rsaParent' to TRUE if the RSA SRK is specified and the SRK
+ * handle is not persistent. Otherwise, remove 'rsaParent'.
+ */
+ if (args->tpm2_srk == 0 && args->srk_type.type == TPM_ALG_RSA)
+ ret = asn1_write_value (tpm2key, "rsaParent", "TRUE", 1);
+ else
+ ret = asn1_write_value (tpm2key, "rsaParent", NULL, 0);
+
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'rsaParent': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Set the pubkey */
+ ret = asn1_write_value (tpm2key, "pubkey", pub_buf.data, pub_buf.size);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'pubkey': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Set the privkey */
+ ret = asn1_write_value (tpm2key, "privkey", priv_buf.data, priv_buf.size);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "Failed to set 'privkey': 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ /* Create the DER binary */
+ der_buf_size = 0;
+ ret = asn1_der_coding (tpm2key, "", NULL, &der_buf_size, NULL);
+ if (ret != ASN1_MEM_ERROR)
+ {
+ fprintf (stderr, "Failed to get DER size: 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ der_buf = grub_malloc (der_buf_size);
+ if (der_buf == NULL)
+ {
+ fprintf (stderr, "Failed to allocate memory for DER encoding\n");
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ goto error;
+ }
+
+ ret = asn1_der_coding (tpm2key, "", der_buf, &der_buf_size, NULL);
+ if (ret != ASN1_SUCCESS)
+ {
+ fprintf (stderr, "DER coding error: 0x%x\n", ret);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto error;
+ }
+
+ err = protect_write_file (args->tpm2_outfile, der_buf, der_buf_size);
+ if (err != GRUB_ERR_NONE)
+ fprintf (stderr, "Could not write tpm2key file (Error: %u).\n", errno);
+
+ error:
+ grub_free (der_buf);
+
+ if (tpm2key)
+ asn1_delete_structure (&tpm2key);
+
+ return err;
+}
+
+static grub_err_t
+protect_tpm2_export_sealed_key (const char *filepath,
+ tpm2_sealed_key_t *sealed_key)
+{
+ grub_err_t err;
+ struct grub_tpm2_buffer buf;
+
+ grub_tpm2_buffer_init (&buf);
+ grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&buf, &sealed_key->public);
+ grub_Tss2_MU_TPM2B_Marshal (&buf, sealed_key->private.size,
+ sealed_key->private.buffer);
+ if (buf.error != 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ err = protect_write_file (filepath, buf.data, buf.size);
+ if (err != GRUB_ERR_NONE)
+ fprintf (stderr, "Could not write sealed key file (Error: %u).\n", errno);
+
+ return err;
+}
+
+static grub_err_t
+protect_tpm2_add (struct grub_protect_args *args)
+{
+ grub_err_t err;
+ grub_uint8_t *key = NULL;
+ grub_size_t key_size;
+ TPM_HANDLE_t srk;
+ TPM2B_DIGEST_t policy_digest;
+ tpm2_sealed_key_t sealed_key;
+
+ err = protect_tpm2_open_device (args->tpm2_device);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = protect_read_file (args->tpm2_keyfile, (void **)&key, &key_size);
+ if (err != GRUB_ERR_NONE)
+ goto exit1;
+
+ if (key_size > TPM_MAX_SYM_DATA)
+ {
+ fprintf (stderr, "Input key size larger than %u bytes.\n", TPM_MAX_SYM_DATA);
+ err = GRUB_ERR_OUT_OF_RANGE;
+ goto exit2;
+ }
+
+ err = protect_tpm2_get_srk (args, &srk);
+ if (err != GRUB_ERR_NONE)
+ goto exit2;
+
+ err = protect_tpm2_get_policy_digest (args, &policy_digest);
+ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ err = protect_tpm2_seal (&policy_digest, srk, key, key_size, &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ if (args->tpm2_tpm2key != 0)
+ err = protect_tpm2_export_tpm2key (args, &sealed_key);
+ else
+ err = protect_tpm2_export_sealed_key (args->tpm2_outfile, &sealed_key);
+ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ exit3:
+ grub_tpm2_flushcontext (srk);
+
+ exit2:
+ grub_free (key);
+
+ exit1:
+ protect_tpm2_close_device ();
+
+ return err;
+}
+
+static grub_err_t
+protect_tpm2_remove (struct grub_protect_args *args)
+{
+ TPM_RC_t rc;
+ TPM2B_PUBLIC_t public;
+ TPMS_AUTH_COMMAND_t authCommand = { 0 };
+ grub_err_t err;
+
+ if (args->tpm2_evict == 0)
+ {
+ printf ("--tpm2-evict not specified, nothing to do.\n");
+ return GRUB_ERR_NONE;
+ }
+
+ err = protect_tpm2_open_device (args->tpm2_device);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /* Find SRK */
+ rc = grub_tpm2_readpublic (args->tpm2_srk, NULL, &public);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "SRK with handle 0x%x not found.\n", args->tpm2_srk);
+ err = GRUB_ERR_BAD_ARGUMENT;
+ goto exit1;
+ }
+
+ /* Evict SRK */
+ authCommand.sessionHandle = TPM_RS_PW;
+
+ rc = grub_tpm2_evictcontrol (TPM_RH_OWNER, args->tpm2_srk, &authCommand, args->tpm2_srk, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ fprintf (stderr, "Failed to evict SRK with handle 0x%x (TPM2_EvictControl: 0x%x).\n", args->tpm2_srk, rc);
+ err = GRUB_ERR_BAD_DEVICE;
+ goto exit2;
+ }
+
+ err = GRUB_ERR_NONE;
+
+ exit2:
+ grub_tpm2_flushcontext (args->tpm2_srk);
+
+ exit1:
+ protect_tpm2_close_device ();
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+protect_tpm2_run (struct grub_protect_args *args)
+{
+ switch (args->action)
+ {
+ case GRUB_PROTECT_ACTION_ADD:
+ return protect_tpm2_add (args);
+
+ case GRUB_PROTECT_ACTION_REMOVE:
+ return protect_tpm2_remove (args);
+
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+}
+
+static grub_err_t
+protect_tpm2_args_verify (struct grub_protect_args *args)
+{
+ switch (args->action)
+ {
+ case GRUB_PROTECT_ACTION_ADD:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT)
+ {
+ fprintf (stderr, N_("--tpm2-evict is invalid when --action is 'add'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_keyfile == NULL)
+ {
+ fprintf (stderr, N_("--tpm2-keyfile must be specified.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_outfile == NULL)
+ {
+ fprintf (stderr, N_("--tpm2-outfile must be specified.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_device == NULL)
+ args->tpm2_device = "/dev/tpm0";
+
+ if (args->tpm2_pcr_count == 0)
+ {
+ args->tpm2_pcrs[0] = 7;
+ args->tpm2_pcr_count = 1;
+ }
+
+ if (args->srk_type.type == TPM_ALG_ERROR)
+ {
+ args->srk_type.type = TPM_ALG_ECC;
+ args->srk_type.detail.ecc_curve = TPM_ECC_NIST_P256;
+ }
+
+ if (args->tpm2_bank == TPM_ALG_ERROR)
+ args->tpm2_bank = TPM_ALG_SHA256;
+
+ break;
+
+ case GRUB_PROTECT_ACTION_REMOVE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC)
+ {
+ fprintf (stderr, N_("--tpm2-asymmetric is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK)
+ {
+ fprintf (stderr, N_("--tpm2-bank is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE)
+ {
+ fprintf (stderr, N_("--tpm2-keyfile is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE)
+ {
+ fprintf (stderr, N_("--tpm2-outfile is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS)
+ {
+ fprintf (stderr, N_("--tpm2-pcrs is invalid when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_srk == 0)
+ {
+ fprintf (stderr, N_("--tpm2-srk is not specified when --action is 'remove'.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (args->tpm2_device == NULL)
+ args->tpm2_device = "/dev/tpm0";
+
+ break;
+
+ default:
+ fprintf (stderr, N_("The TPM2 key protector only supports the following actions: add, remove.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static error_t
+protect_argp_parser (int key, char *arg, struct argp_state *state)
+{
+ grub_err_t err;
+ struct grub_protect_args *args = state->input;
+
+ switch (key)
+ {
+ case GRUB_PROTECT_OPT_ACTION:
+ if (args->args & GRUB_PROTECT_ARG_ACTION)
+ {
+ fprintf (stderr, N_("--action|-a can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ if (grub_strcmp (arg, "add") == 0)
+ args->action = GRUB_PROTECT_ACTION_ADD;
+ else if (grub_strcmp (arg, "remove") == 0)
+ args->action = GRUB_PROTECT_ACTION_REMOVE;
+ else
+ {
+ fprintf (stderr, N_("'%s' is not a valid action.\n"), arg);
+ return EINVAL;
+ }
+
+ args->args |= GRUB_PROTECT_ARG_ACTION;
+ break;
+
+ case GRUB_PROTECT_OPT_PROTECTOR:
+ if (args->args & GRUB_PROTECT_ARG_PROTECTOR)
+ {
+ fprintf (stderr, N_("--protector|-p can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ if (grub_strcmp (arg, "tpm2") == 0)
+ args->protector = GRUB_PROTECT_TYPE_TPM2;
+ else
+ {
+ fprintf (stderr, N_("'%s' is not a valid protector.\n"), arg);
+ return EINVAL;
+ }
+
+ args->args |= GRUB_PROTECT_ARG_PROTECTOR;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_DEVICE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_DEVICE)
+ {
+ fprintf (stderr, N_("--tpm2-device can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ args->tpm2_device = xstrdup(arg);
+ args->args |= GRUB_PROTECT_ARG_TPM2_DEVICE;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_PCRS:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_PCRS)
+ {
+ fprintf (stderr, N_("--tpm2-pcrs can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ err = grub_tpm2_protector_parse_pcrs (arg, args->tpm2_pcrs,
+ &args->tpm2_pcr_count);
+ if (err != GRUB_ERR_NONE)
+ {
+ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
+
+ args->args |= GRUB_PROTECT_ARG_TPM2_PCRS;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_SRK:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_SRK)
+ {
+ fprintf (stderr, N_("--tpm2-srk can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ err = grub_tpm2_protector_parse_tpm_handle (arg, &args->tpm2_srk);
+ if (err != GRUB_ERR_NONE)
+ {
+ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
+
+ args->args |= GRUB_PROTECT_ARG_TPM2_SRK;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_ASYMMETRIC:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_ASYMMETRIC)
+ {
+ fprintf (stderr, N_("--tpm2-asymmetric can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ err = grub_tpm2_protector_parse_asymmetric (arg, &args->srk_type);
+ if (err != GRUB_ERR_NONE)
+ {
+ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
+
+ args->args |= GRUB_PROTECT_ARG_TPM2_ASYMMETRIC;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_BANK:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_BANK)
+ {
+ fprintf (stderr, N_("--tpm2-bank can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ err = grub_tpm2_protector_parse_bank (arg, &args->tpm2_bank);
+ if (err != GRUB_ERR_NONE)
+ {
+ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
+
+ args->args |= GRUB_PROTECT_ARG_TPM2_BANK;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_KEYFILE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_KEYFILE)
+ {
+ fprintf (stderr, N_("--tpm2-keyfile can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ args->tpm2_keyfile = xstrdup(arg);
+ args->args |= GRUB_PROTECT_ARG_TPM2_KEYFILE;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_OUTFILE:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_OUTFILE)
+ {
+ fprintf (stderr, N_("--tpm2-outfile can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ args->tpm2_outfile = xstrdup(arg);
+ args->args |= GRUB_PROTECT_ARG_TPM2_OUTFILE;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_EVICT:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_EVICT)
+ {
+ fprintf (stderr, N_("--tpm2-evict can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ args->tpm2_evict = 1;
+ args->args |= GRUB_PROTECT_ARG_TPM2_EVICT;
+ break;
+
+ case GRUB_PROTECT_OPT_TPM2_TPM2KEY:
+ if (args->args & GRUB_PROTECT_ARG_TPM2_TPM2KEY)
+ {
+ fprintf (stderr, N_("--tpm2-tpm2key can only be specified once.\n"));
+ return EINVAL;
+ }
+
+ args->tpm2_tpm2key = 1;
+ args->args |= GRUB_PROTECT_ARG_TPM2_TPM2KEY;
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static grub_err_t
+protect_args_verify (struct grub_protect_args *args)
+{
+ if (args->action == GRUB_PROTECT_ACTION_ERROR)
+ {
+ fprintf (stderr, N_("--action is mandatory.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ /* At the moment, the only configurable key protector is the TPM2 one, so it
+ * is the only key protector supported by this tool. */
+ if (args->protector != GRUB_PROTECT_TYPE_TPM2)
+ {
+ fprintf (stderr, N_("--protector is mandatory and only 'tpm2' is currently supported.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ switch (args->protector)
+ {
+ case GRUB_PROTECT_TYPE_TPM2:
+ return protect_tpm2_args_verify (args);
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+protect_dispatch (struct grub_protect_args *args)
+{
+ switch (args->protector)
+ {
+ case GRUB_PROTECT_TYPE_TPM2:
+ return protect_tpm2_run (args);
+ default:
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+}
+
+static void
+protect_init (int *argc, char **argv[])
+{
+ grub_util_host_init (argc, argv);
+
+ grub_util_biosdisk_init (NULL);
+
+ grub_init_all ();
+
+ grub_lvm_fini ();
+ grub_mdraid09_fini ();
+ grub_mdraid1x_fini ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
+ grub_mdraid09_init ();
+ grub_mdraid1x_init ();
+ grub_lvm_init ();
+}
+
+static void
+protect_fini (void)
+{
+ grub_fini_all ();
+ grub_util_biosdisk_fini ();
+}
+
+static struct argp grub_protect_argp =
+{
+ .options = grub_protect_options,
+ .parser = protect_argp_parser,
+ .args_doc = NULL,
+ .doc =
+ N_("Protect a cleartext key using a GRUB key protector that can retrieve "
+ "the key during boot to unlock fully-encrypted disks automatically."),
+ .children = NULL,
+ .help_filter = NULL,
+ .argp_domain = NULL
+};
+
+int
+main (int argc, char *argv[])
+{
+ grub_err_t err;
+ struct grub_protect_args args = { 0 };
+
+ if (argp_parse (&grub_protect_argp, argc, argv, 0, 0, &args) != 0)
+ {
+ fprintf (stderr, N_("Could not parse arguments.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ protect_init (&argc, &argv);
+
+ err = protect_args_verify (&args);
+ if (err != GRUB_ERR_NONE)
+ goto exit;
+
+ err = protect_dispatch (&args);
+ if (err != GRUB_ERR_NONE)
+ goto exit;
+
+ exit:
+ protect_fini ();
+
+ return err;
+}
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 25/33] tpm2_key_protector: Support authorized policy
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (23 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 24/33] util/grub-protect: Add new tool Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-16 16:08 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 26/33] tpm2_key_protector: Implement NV index Gary Lin via Grub-devel
` (9 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
This commit handles the TPM2_PolicyAuthorize command from the key file
in TPM 2.0 Key File format.
TPM2_PolicyAuthorize is the essential command to support authorized
policy which allows the users to sign TPM policies with their own keys.
Per TPM 2.0 Key File(*1), CommandPolicy for TPM2_PolicyAuthorize
comprises 'TPM2B_PUBLIC pubkey', 'TPM2B_DIGEST policy_ref', and
'TPMT_SIGNATURE signature'. To verify the signature, the current policy
digest is hashed with the hash algorithm written in 'signature', and then
'signature' is verified with the hashed policy digest and 'pubkey'. Once
TPM accepts 'signature', TPM2_PolicyAuthorize is invoked to authorize the
signed policy.
To create the key file with authorized policy, here are the pcr-oracle(*2)
commands:
# Generate the RSA key and create the authorized policy file
$ pcr-oracle \
--rsa-generate-key \
--private-key policy-key.pem \
--auth authorized.policy \
create-authorized-policy 0,2,4,7,9
# Seal the secret with the authorized policy
$ pcr-oracle \
--key-format tpm2.0 \
--auth authorized.policy \
--input disk-secret.txt \
--output sealed.key \
seal-secret
# Sign the predicted PCR policy
$ pcr-oracle \
--key-format tpm2.0 \
--private-key policy-key.pem \
--from eventlog \
--stop-event "grub-file=grub.cfg" \
--after \
--input sealed.key \
--output sealed.tpm \
sign 0,2,4,7,9
Then specify the key file and the key protector to grub.cfg in the EFI
system partition:
tpm2_key_protector_init -a RSA --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
cryptomount -u <PART_UUID> -P tpm2
For any change in the boot components, just run the 'sign' command again
to update the signature in sealed.tpm, and TPM can unseal the key file
with the updated PCR policy.
(*1) https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
(*2) https://github.com/okirch/pcr-oracle
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
.../commands/tpm2_key_protector/module.c | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
index 909c3cc6a..eefa71068 100644
--- a/grub-core/commands/tpm2_key_protector/module.c
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -618,6 +618,73 @@ tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION_t session, struct grub_tpm2_buffe
return GRUB_ERR_NONE;
}
+static grub_err_t
+tpm2_protector_policyauthorize (TPMI_SH_AUTH_SESSION_t session, struct grub_tpm2_buffer *cmd_buf)
+{
+ TPM2B_PUBLIC_t pubkey;
+ TPM2B_DIGEST_t policy_ref;
+ TPMT_SIGNATURE_t signature;
+ TPM2B_DIGEST_t pcr_policy;
+ TPM2B_DIGEST_t pcr_policy_hash;
+ TPMI_ALG_HASH_t sig_hash;
+ TPMT_TK_VERIFIED_t verification_ticket;
+ TPM_HANDLE_t pubkey_handle = 0;
+ TPM2B_NAME_t pubname;
+ TPM_RC_t rc;
+ grub_err_t err;
+
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (cmd_buf, &pubkey);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (cmd_buf, &policy_ref);
+ grub_Tss2_MU_TPMT_SIGNATURE_Unmarshal (cmd_buf, &signature);
+ if (cmd_buf->error != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to unmarshal the buffer for TPM2_PolicyAuthorize");
+
+ /* Retrieve Policy Digest */
+ rc = grub_tpm2_policygetdigest (session, NULL, &pcr_policy, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to get policy digest (TPM2_PolicyGetDigest: 0x%x).", rc);
+
+ /* Calculate the digest of the polcy for VerifySignature */
+ sig_hash = TPMT_SIGNATURE_get_hash_alg (&signature);
+ if (sig_hash == TPM_ALG_NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Failed to get the hash algorithm of the signature");
+
+ rc = grub_tpm2_hash (NULL, (TPM2B_MAX_BUFFER_t *) &pcr_policy, sig_hash,
+ TPM_RH_NULL, &pcr_policy_hash, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to create PCR policy hash (TPM2_Hash: 0x%x)", rc);
+
+ /* Load the public key */
+ rc = grub_tpm2_loadexternal (NULL, NULL, &pubkey, TPM_RH_OWNER, &pubkey_handle, &pubname, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "Failed to load public key (TPM2_LoadExternal: 0x%x)", rc);
+
+ /* Verify the signature against the public key and the policy digest */
+ rc = grub_tpm2_verifysignature (pubkey_handle, NULL, &pcr_policy_hash, &signature,
+ &verification_ticket, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "Failed to verify signature (TPM2_VerifySignature: 0x%x)", rc);
+ goto error;
+ }
+
+ /* Authorize the signed policy with the public key and the verification ticket */
+ rc = grub_tpm2_policyauthorize (session, NULL, &pcr_policy, &policy_ref, &pubname,
+ &verification_ticket, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "Failed to authorize PCR policy (TPM2_PolicyAuthorize: 0x%x)", rc);
+ goto error;
+ }
+
+ err = GRUB_ERR_NONE;
+
+ error:
+ grub_tpm2_flushcontext (pubkey_handle);
+
+ return err;
+}
+
static grub_err_t
tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION_t session)
{
@@ -636,6 +703,9 @@ tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION_t s
case TPM_CC_PolicyPCR:
err = tpm2_protector_policypcr (session, &buf);
break;
+ case TPM_CC_PolicyAuthorize:
+ err = tpm2_protector_policyauthorize (session, &buf);
+ break;
default:
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unknown TPM Command: 0x%x", policy->cmd_code);
}
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 26/33] tpm2_key_protector: Implement NV index
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (24 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 25/33] tpm2_key_protector: Support authorized policy Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-16 16:11 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 27/33] cryptodisk: Fallback to passphrase Gary Lin via Grub-devel
` (8 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Patrick Colp <patrick.colp@oracle.com>
Currently with the TPM2 protector, only SRK mode is supported and
NV index support is just a stub. Implement the NV index option.
Note: This only extends support on the unseal path. grub2_protect
has not been updated. tpm2-tools can be used to insert a key into
the NV index.
An example of inserting a key using tpm2-tools:
# Get random key.
tpm2_getrandom 32 > key.dat
# Create primary object.
tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx
# Create policy object. `pcrs.dat` contains the PCR values to seal against.
tpm2_startauthsession -S session.dat
tpm2_policypcr -S session.dat -l sha256:7,11 -f pcrs.dat -L policy.dat
tpm2_flushcontext session.dat
# Seal key into TPM.
cat key.dat | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-
tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx
tpm2_evictcontrol -C o -c sealing.ctx 0x81000000
Then to unseal the key in grub, add this to grub.cfg:
tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=7,11
cryptomount -u <UUID> --protector tpm2
Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
.../commands/tpm2_key_protector/module.c | 23 +++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
index eefa71068..0ad40bcb6 100644
--- a/grub-core/commands/tpm2_key_protector/module.c
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -973,11 +973,26 @@ tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx,
}
static grub_err_t
-tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx __attribute__ ((unused)),
- grub_uint8_t **key __attribute__ ((unused)),
- grub_size_t *key_size __attribute__ ((unused)))
+tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx,
+ grub_uint8_t **key, grub_size_t *key_size)
{
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "NV Index mode is not implemented yet");
+ TPM_HANDLE_t sealed_handle = ctx->nv;
+ tpm2key_policy_t policy_seq = NULL;
+ grub_err_t err;
+
+ /* Create a basic policy sequence based on the given PCR selection */
+ err = tpm2_protector_simple_policy_seq (ctx, &policy_seq);
+ if (err != GRUB_ERR_NONE)
+ goto exit;
+
+ err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size);
+
+ exit:
+ grub_tpm2_flushcontext (sealed_handle);
+
+ grub_tpm2key_free_policy_seq (policy_seq);
+
+ return err;
}
static grub_err_t
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 27/33] cryptodisk: Fallback to passphrase
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (25 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 26/33] tpm2_key_protector: Implement NV index Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-16 16:14 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 28/33] cryptodisk: wipe out the cached keys from protectors Gary Lin via Grub-devel
` (7 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
From: Patrick Colp <patrick.colp@oracle.com>
If a protector is specified, but it fails to unlock the disk, fall back
to asking for the passphrase.
Before requesting the passphrase, the error from the key protector(s)
has to be cleared, or the later code (e.g., LUKS code) may stop as
'grub_errno' is set. This commit prints error from the key protector(s)
and sets 'grub_errno' to 'GRUB_ERR_NONE' to have a fresh start.
Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/disk/cryptodisk.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 6f7394942..4219f1fb6 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1167,6 +1167,10 @@ grub_cryptodisk_scan_device_real (const char *name,
ret = cr->recover_key (source, dev, cargs);
if (ret != GRUB_ERR_NONE)
{
+ /* Reset key data to trigger the passphrase prompt later */
+ cargs->key_data = NULL;
+ cargs->key_len = 0;
+
part = grub_partition_get_name (source->partition);
grub_dprintf ("cryptodisk",
"recovered a key from key protector %s but it "
@@ -1192,7 +1196,6 @@ grub_cryptodisk_scan_device_real (const char *name,
source->name, source->partition != NULL ? "," : "",
part != NULL ? part : N_("UNKNOWN"), dev->uuid);
grub_free (part);
- goto error;
}
if (cargs->key_len)
@@ -1207,6 +1210,24 @@ grub_cryptodisk_scan_device_real (const char *name,
unsigned long tries = 3;
const char *tries_env;
+ /*
+ * Print the error from key protectors and clear grub_errno.
+ *
+ * Since '--protector' cannot coexist with '--password' and
+ * '--key-file', in case key protectors fail, only
+ * "cargs->key_len == 0" is expected, so cryptomount falls back
+ * here to request the passphrase.
+ *
+ * To avoid the error from key protectors stops the further code,
+ * print the error to notify the user why key protectors fail and
+ * clear grub_errno to have a fresh start.
+ */
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ }
+
askpass = 1;
cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
if (cargs->key_data == NULL)
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 28/33] cryptodisk: wipe out the cached keys from protectors
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (26 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 27/33] cryptodisk: Fallback to passphrase Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 29/33] diskfilter: look up cryptodisk devices first Gary Lin via Grub-devel
` (6 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko, Fabian Vogt
An attacker may insert a malicious disk with the same crypto UUID and
trick grub2 to mount the fake root. Even though the key from the key
protector fails to unlock the fake root, it's not wiped out cleanly so
the attacker could dump the memory to retrieve the secret key. To defend
such attack, wipe out the cached key when we don't need it.
Cc: Fabian Vogt <fvogt@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 4219f1fb6..5fc41979e 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1405,7 +1405,11 @@ grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs)
return;
for (i = 0; cargs->protectors[i]; i++)
- grub_free (cargs->key_cache[i].key);
+ {
+ if (cargs->key_cache[i].key)
+ grub_memset (cargs->key_cache[i].key, 0, cargs->key_cache[i].key_len);
+ grub_free (cargs->key_cache[i].key);
+ }
grub_free (cargs->key_cache);
}
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 29/33] diskfilter: look up cryptodisk devices first
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (27 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 28/33] cryptodisk: wipe out the cached keys from protectors Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-16 16:19 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 30/33] tpm2_key_protector: Add grub-emu support Gary Lin via Grub-devel
` (5 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko, Fabian Vogt
When using disk auto-unlocking with TPM 2.0, the typical grub.cfg may
look like this:
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
cryptomount -u <PART-UUID> -P tpm2
search --fs-uuid --set=root <FS-UUID>
Since the disk search order is based on the order of module loading, the
attacker could insert a malicious disk with the same FS-UUID root to
trick grub2 to boot into the malicious root and further dump memory to
steal the unsealed key.
Do defend against such an attack, we can specify the hint provided by
'grub-probe' to search the encrypted partition first:
search --fs-uuid --set=root --hint='cryptouuid/<PART-UUID>' <FS-UUID>
However, for LVM on an encrypted partition, the search hint provided by
'grub-probe' is:
--hint='lvmid/<VG-UUID>/<LV-UUID>'
It doesn't guarantee to look up the logical volume from the encrypted
partition, so the attacker may have the chance to fool grub2 to boot
into the malicious disk.
To minimize the attack surface, this commit tweaks the disk device search
in diskfilter to look up cryptodisk devices first and then others, so
that the auto-unlocked disk will be found first, not the attacker's disk.
Cc: Fabian Vogt <fvogt@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/disk/diskfilter.c | 31 ++++++++++++++++++++++---------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
index 21e239511..606195c26 100644
--- a/grub-core/disk/diskfilter.c
+++ b/grub-core/disk/diskfilter.c
@@ -226,15 +226,28 @@ scan_devices (const char *arname)
int need_rescan;
for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
- for (p = grub_disk_dev_list; p; p = p->next)
- if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
- && p->disk_iterate)
- {
- if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
- return;
- if (arname && is_lv_readable (find_lv (arname), 1))
- return;
- }
+ {
+ /* look up the crytodisk devices first */
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->id == GRUB_DISK_DEVICE_CRYPTODISK_ID && p->disk_iterate)
+ {
+ if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
+ return;
+ if (arname && is_lv_readable (find_lv (arname), 1))
+ return;
+ break;
+ }
+
+ /* check the devices other than crytodisk */
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID && p->disk_iterate)
+ {
+ if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
+ return;
+ if (arname && is_lv_readable (find_lv (arname), 1))
+ return;
+ }
+ }
scan_depth = 0;
need_rescan = 1;
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 30/33] tpm2_key_protector: Add grub-emu support
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (28 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 29/33] diskfilter: look up cryptodisk devices first Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-17 17:57 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 31/33] tests: Add tpm2_key_protector_test Gary Lin via Grub-devel
` (4 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
As a preparation to test tpm2_key_protector with grub-emu, the new
option, --tpm-device, is introduced to specify the TPM device for
grub-emu so that grub-emu can share the emulated TPM device with
the host.
Since grub-emu can directly access the device node on host, it's easy to
implement the essential TCG2 command submission function with the
read/write functions and enable tpm2_key_protector module for grub-emu,
so that we can further test TPM2 key unsealing with grub-emu.
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/Makefile.core.def | 3 ++
grub-core/kern/emu/main.c | 11 ++++++-
grub-core/kern/emu/misc.c | 51 +++++++++++++++++++++++++++++++++
grub-core/lib/tss2/tcg2_emu.c | 54 +++++++++++++++++++++++++++++++++++
include/grub/emu/misc.h | 5 ++++
5 files changed, 123 insertions(+), 1 deletion(-)
create mode 100644 grub-core/lib/tss2/tcg2_emu.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 97ae4e49b..40427165e 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2574,7 +2574,9 @@ module = {
common = lib/tss2/tpm2_cmd.c;
common = lib/tss2/tss2.c;
efi = lib/efi/tcg2.c;
+ emu = lib/tss2/tcg2_emu.c;
enable = efi;
+ enable = emu;
cppflags = '-I$(srcdir)/lib/tss2';
};
@@ -2586,6 +2588,7 @@ module = {
common = commands/tpm2_key_protector/tpm2key_asn1_tab.c;
/* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */
enable = efi;
+ enable = emu;
cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub';
};
diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
index 855b11c3d..c10838613 100644
--- a/grub-core/kern/emu/main.c
+++ b/grub-core/kern/emu/main.c
@@ -55,7 +55,7 @@
static jmp_buf main_env;
/* Store the prefix specified by an argument. */
-static char *root_dev = NULL, *dir = NULL;
+static char *root_dev = NULL, *dir = NULL, *tpm_dev = NULL;
grub_addr_t grub_modbase = 0;
@@ -108,6 +108,7 @@ static struct argp_option options[] = {
{"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
{"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
{"kexec", 'X', 0, 0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0},
+ {"tpm-device", 't', N_("DEV"), 0, N_("Set TPM device."), 0},
{ 0, 0, 0, 0, 0, 0 }
};
@@ -168,6 +169,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
case 'X':
grub_util_set_kexecute ();
break;
+ case 't':
+ free (tpm_dev);
+ tpm_dev = xstrdup (arg);
+ break;
case ARGP_KEY_ARG:
{
@@ -276,6 +281,9 @@ main (int argc, char *argv[])
dir = xstrdup (dir);
+ if (tpm_dev)
+ grub_util_tpm_open (tpm_dev);
+
/* Start GRUB! */
if (setjmp (main_env) == 0)
grub_main ();
@@ -283,6 +291,7 @@ main (int argc, char *argv[])
grub_fini_all ();
grub_hostfs_fini ();
grub_host_fini ();
+ grub_util_tpm_close ();
grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
index 521220b49..1db24fde7 100644
--- a/grub-core/kern/emu/misc.c
+++ b/grub-core/kern/emu/misc.c
@@ -28,6 +28,8 @@
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <grub/mm.h>
#include <grub/err.h>
@@ -41,6 +43,8 @@
int verbosity;
int kexecute;
+static int grub_util_tpm_fd = -1;
+
void
grub_util_warn (const char *fmt, ...)
{
@@ -230,3 +234,50 @@ grub_util_get_kexecute (void)
{
return kexecute;
}
+
+grub_err_t
+grub_util_tpm_open (const char *tpm_dev)
+{
+ if (grub_util_tpm_fd != -1)
+ return GRUB_ERR_NONE;
+
+ grub_util_tpm_fd = open (tpm_dev, O_RDWR);
+ if (grub_util_tpm_fd == -1)
+ grub_util_error (_("cannot open TPM device '%s': %s"), tpm_dev, strerror (errno));
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_util_tpm_close (void)
+{
+ int err;
+
+ if (grub_util_tpm_fd == -1)
+ return GRUB_ERR_NONE;
+
+ err = close (grub_util_tpm_fd);
+ if (err != GRUB_ERR_NONE)
+ grub_util_error (_("cannot close TPM device: %s"), strerror (errno));
+
+ grub_util_tpm_fd = -1;
+ return GRUB_ERR_NONE;
+}
+
+grub_size_t
+grub_util_tpm_read (void *output, grub_size_t size)
+{
+ if (grub_util_tpm_fd == -1)
+ return -1;
+
+ return read (grub_util_tpm_fd, output, size);
+}
+
+grub_size_t
+grub_util_tpm_write (const void *input, grub_size_t size)
+{
+ if (grub_util_tpm_fd == -1)
+ return -1;
+
+ return write (grub_util_tpm_fd, input, size);
+}
diff --git a/grub-core/lib/tss2/tcg2_emu.c b/grub-core/lib/tss2/tcg2_emu.c
new file mode 100644
index 000000000..6bf4195d7
--- /dev/null
+++ b/grub-core/lib/tss2/tcg2_emu.c
@@ -0,0 +1,54 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 SUSE LLC
+ * Copyright (C) 2024 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/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/tpm.h>
+#include <grub/mm.h>
+#include <grub/emu/misc.h>
+
+#include <tss2_buffer.h>
+#include <tcg2.h>
+
+grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size)
+{
+ if (size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *size = GRUB_TPM2_BUFFER_CAPACITY;
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
+ grub_size_t output_size, grub_uint8_t *output)
+{
+ static const grub_size_t header_size = sizeof (grub_uint16_t) +
+ (2 * sizeof(grub_uint32_t));
+
+ if (grub_util_tpm_write (input, input_size) != input_size)
+ return GRUB_ERR_BAD_DEVICE;
+
+ if (grub_util_tpm_read (output, output_size) < header_size)
+ return GRUB_ERR_BAD_DEVICE;
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h
index fa959ebe7..fefbec499 100644
--- a/include/grub/emu/misc.h
+++ b/include/grub/emu/misc.h
@@ -75,4 +75,9 @@ grub_util_fopen (const char *path, const char *mode);
int grub_util_file_sync (FILE *f);
+grub_err_t grub_util_tpm_open (const char *tpm_dev);
+grub_err_t grub_util_tpm_close (void);
+grub_size_t EXPORT_FUNC(grub_util_tpm_read) (void *output, grub_size_t size);
+grub_size_t EXPORT_FUNC(grub_util_tpm_write) (const void *input, grub_size_t size);
+
#endif /* GRUB_EMU_MISC_H */
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 31/33] tests: Add tpm2_key_protector_test
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (29 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 30/33] tpm2_key_protector: Add grub-emu support Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 32/33] cryptodisk: Document the '-P' option Gary Lin via Grub-devel
` (3 subsequent siblings)
34 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
For the tpm2_key_protector module, the TCG2 command submission function
is the only difference between a QEMU instance and grub-emu. To test
TPM2 key unsealing with a QEMU instance, it requires an extra OS image
to invoke grub-protect to seal the LUKS key, rather than a simple
grub-shell rescue CD image. On the other hand, grub-emu can share the
emulated TPM2 device with the host, so that we can seal the LUKS key on
host and test key unsealing with grub-emu.
This test script firstly creates a simple LUKS image to be loaded as a
loopback device in grub-emu. Then an emulated TPM2 device is created by
"swtpm chardev" and PCR 0 and 1 are extended.
There are several test cases in the script to test various settings. Each
test case uses grub-protect or tpm2-tools to seal the LUKS password
with PCR 0 and PCR 1. Then grub-emu is launched to load the LUKS image,
try to mount the image with tpm2_key_protector_init and cryptomount, and
verify the result.
Based on the idea from Michael Chang.
Cc: Michael Chang <mchang@suse.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Glenn Washburn <development@efficientek.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
Makefile.util.def | 6 +
tests/tpm2_key_protector_test.in | 389 +++++++++++++++++++++++++++++++
tests/util/grub-shell.in | 6 +-
3 files changed, 400 insertions(+), 1 deletion(-)
create mode 100644 tests/tpm2_key_protector_test.in
diff --git a/Makefile.util.def b/Makefile.util.def
index 074c0aff7..038253b37 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -1290,6 +1290,12 @@ script = {
common = tests/asn1_test.in;
};
+script = {
+ testcase = native;
+ name = tpm2_key_protector_test;
+ common = tests/tpm2_key_protector_test.in;
+};
+
program = {
testcase = native;
name = example_unit_test;
diff --git a/tests/tpm2_key_protector_test.in b/tests/tpm2_key_protector_test.in
new file mode 100644
index 000000000..a92e5f498
--- /dev/null
+++ b/tests/tpm2_key_protector_test.in
@@ -0,0 +1,389 @@
+#! @BUILD_SHEBANG@ -e
+
+# Test GRUBs ability to unseal a LUKS key with TPM 2.0
+# Copyright (C) 2024 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/>.
+
+grubshell=@builddir@/grub-shell
+
+. "@builddir@/grub-core/modinfo.sh"
+
+if [ x${grub_modinfo_platform} != xemu ]; then
+ exit 77
+fi
+
+builddir="@builddir@"
+
+# Force build directory components
+PATH="${builddir}:${PATH}"
+export PATH
+
+if [ "x${EUID}" = "x" ] ; then
+ EUID=`id -u`
+fi
+
+if [ "${EUID}" != 0 ] ; then
+ echo "not root; cannot test tpm2."
+ exit 99
+fi
+
+if ! command -v cryptsetup >/dev/null 2>&1; then
+ echo "cryptsetup not installed; cannot test tpm2."
+ exit 99
+fi
+
+if ! grep -q tpm_vtpm_proxy /proc/modules && ! modprobe tpm_vtpm_proxy; then
+ echo "no tpm_vtpm_proxy support; cannot test tpm2."
+ exit 99
+fi
+
+if ! command -v swtpm >/dev/null 2>&1; then
+ echo "swtpm not installed; cannot test tpm2."
+ exit 99
+fi
+
+if ! command -v tpm2_startup >/dev/null 2>&1; then
+ echo "tpm2-tools not installed; cannot test tpm2."
+ exit 99
+fi
+
+tpm2testdir="`mktemp -d "${TMPDIR:-/tmp}/$(basename "$0").XXXXXXXXXX"`" || exit 99
+
+disksize=20M
+
+luksfile=${tpm2testdir}/luks.disk
+lukskeyfile=${tpm2testdir}/password.txt
+
+# Choose a low iteration number to reduce the time to decrypt the disk
+csopt="--type luks2 --pbkdf pbkdf2 --iter-time 1000"
+
+tpm2statedir=${tpm2testdir}/tpm
+tpm2ctrl=${tpm2statedir}/ctrl
+tpm2log=${tpm2statedir}/logfile
+
+sealedkey=${tpm2testdir}/sealed.tpm
+
+timeout=20
+
+testoutput=${tpm2testdir}/testoutput
+
+vtext="TEST VERIFIED"
+
+ret=0
+
+# Create the password file
+echo -n "top secret" > "${lukskeyfile}"
+
+# Setup LUKS2 image
+truncate -s ${disksize} "${luksfile}" || exit 99
+cryptsetup luksFormat -q ${csopt} "${luksfile}" "${lukskeyfile}" || exit 99
+
+# Write vtext into the first block of the LUKS2 image
+luksdev=/dev/mapper/`basename "${tpm2testdir}"`
+cryptsetup open --key-file "${lukskeyfile}" "${luksfile}" `basename "${luksdev}"` || exit 99
+echo "${vtext}" > "${luksdev}"
+cryptsetup close "${luksdev}"
+
+# Shutdown the swtpm instance on exit
+cleanup() {
+ RET=$?
+ if [ -e "${tpm2ctrl}" ]; then
+ swtpm_ioctl -s --unix "${tpm2ctrl}"
+ fi
+ if [ "${RET}" -eq 0 ]; then
+ rm -rf "$tpm2testdir" || :
+ fi
+}
+trap cleanup EXIT INT TERM KILL QUIT
+
+mkdir -p "${tpm2statedir}"
+
+# Create the swtpm chardev instance
+swtpm chardev --vtpm-proxy --tpmstate dir="${tpm2statedir}" \
+ --tpm2 --ctrl type=unixio,path="${tpm2ctrl}" \
+ --flags startup-clear --daemon > "${tpm2log}" || ret=$?
+if [ "${ret}" -ne 0 ]; then
+ echo "Failed to start swtpm chardev: ${ret}" >&2
+ exit 99
+fi
+
+# Wait for tpm2 chardev
+tpm2timeout=${GRUB_TEST_SWTPM_DEFAULT_TIMEOUT:-3}
+for count in `seq 1 ${tpm2timeout}`; do
+ sleep 1
+
+ tpm2dev=$(grep "New TPM device" "${tpm2log}" | cut -d' ' -f 4)
+ if [ -c "${tpm2dev}" ]; then
+ break
+ elif [ "${count}" -eq "${tpm2timeout}" ]; then
+ echo "TPM device did not appear." >&2
+ exit 99
+ fi
+done
+
+# Export the TCTI variable for tpm2-tools
+export TPM2TOOLS_TCTI="device:${tpm2dev}"
+
+# Extend PCR 0
+tpm2_pcrextend 0:sha256=$(echo "test0" | sha256sum | cut -d ' ' -f 1) || exit 99
+
+# Extend PCR 1
+tpm2_pcrextend 1:sha256=$(echo "test1" | sha256sum | cut -d ' ' -f 1) || exit 99
+
+tpm2_seal_unseal() {
+ srk_alg="$1"
+ handle_type="$2"
+ srk_test="$3"
+
+ grub_srk_alg=${srk_alg}
+
+ extra_opt=""
+ extra_grub_opt=""
+
+ persistent_handle="0x81000000"
+
+ grub_cfg=${tpm2testdir}/testcase.cfg
+
+ if [ "${handle_type}" = "persistent" ]; then
+ extra_opt="--tpm2-srk=${persistent_handle}"
+ fi
+
+ if [ "${srk_alg}" != "default" ]; then
+ extra_opt="${extra_opt} --tpm2-asymmetric=${srk_alg}"
+ fi
+
+ # Seal the password with grub-protect
+ grub-protect ${extra_opt} \
+ --tpm2-device="${tpm2dev}" \
+ --action=add \
+ --protector=tpm2 \
+ --tpm2key \
+ --tpm2-bank=sha256 \
+ --tpm2-pcrs=0,1 \
+ --tpm2-keyfile="${lukskeyfile}" \
+ --tpm2-outfile="${sealedkey}" || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to seal the secret key: ${ret}" >&2
+ return 99
+ fi
+
+ # Flip the asymmetric algorithm in grub.cfg to trigger fallback SRKs
+ if [ "${srk_test}" = "fallback_srk" ]; then
+ if [ -z "${srk_alg##RSA*}" ]; then
+ grub_srk_alg="ECC"
+ elif [ -z "${srk_alg##ECC*}" ]; then
+ grub_srk_alg="RSA"
+ fi
+ fi
+
+ if [ "${grub_srk_alg}" != "default" ] && [ "${handle_type}" != "persistent" ]; then
+ extra_grub_opt="-a ${grub_srk_alg}"
+ fi
+
+ # Write the TPM unsealing script
+ cat > "${grub_cfg}" <<EOF
+loopback luks (host)${luksfile}
+tpm2_key_protector_init -T (host)${sealedkey} ${extra_grub_opt}
+if cryptomount -a --protector tpm2; then
+ cat (crypto0)+1
+fi
+EOF
+
+ # Test TPM unsealing with the same PCR
+ ${grubshell} --timeout=${timeout} --emu-opts="-t ${tpm2dev}" < "${grub_cfg}" > "${testoutput}" || ret=$?
+
+ # Remove the persistent handle
+ if [ "${handle_type}" = "persistent" ]; then
+ grub-protect \
+ --tpm2-device="${tpm2dev}" \
+ --protector=tpm2 \
+ --action=remove \
+ --tpm2-srk=${persistent_handle} \
+ --tpm2-evict || :
+ fi
+
+ if [ "${ret}" -eq 0 ]; then
+ if ! grep -q "^${vtext}$" "${testoutput}"; then
+ echo "error: test not verified [`cat ${testoutput}`]" >&2
+ return 1
+ fi
+ else
+ echo "grub-emu exited with error: ${ret}" >&2
+ return 99
+ fi
+}
+
+tpm2_seal_nv () {
+ keyfile="$1"
+ nv_index="$2"
+ pcr_list="$3"
+
+ primary_file=${tpm2testdir}/primary.ctx
+ session_file=${tpm2testdir}/session.dat
+ policy_file=${tpm2testdir}/policy.dat
+ keypub_file=${tpm2testdir}/key.pub
+ keypriv_file=${tpm2testdir}/key.priv
+ name_file=${tpm2testdir}/sealing.name
+ sealing_ctx_file=${tpm2testdir}/sealing.ctx
+
+ # Since we don't run a resource manager on our swtpm instance, it has
+ # to flush the transient handles after tpm2_createprimary, tpm2_create
+ # and tpm2_load to avoid the potential out-of-memory (0x902) errors.
+ # Ref: https://github.com/tpm2-software/tpm2-tools/issues/1338#issuecomment-469689398
+
+ # Create the primary object
+ tpm2_createprimary -Q -C o -g sha256 -G ecc -c "${primary_file}" || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to create the primary object: ${ret}" >&2
+ return 1
+ fi
+ tpm2_flushcontext -t || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to flush the transient handles: ${ret}" >&2
+ return 1
+ fi
+
+ # Create the policy object
+ tpm2_startauthsession -S "${session_file}" || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to start auth session: ${ret}" >&2
+ return 1
+ fi
+ tpm2_policypcr -Q -S "${session_file}" -l "${pcr_list}" -L "${policy_file}" || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to create the policy object: ${ret}" >&2
+ return 1
+ fi
+ tpm2_flushcontext "${session_file}" || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to flush the transient handles: ${ret}" >&2
+ return 1
+ fi
+
+ # Seal the key into TPM
+ tpm2_create -Q \
+ -C "${primary_file}" \
+ -u "${keypub_file}" \
+ -r "${keypriv_file}" \
+ -L "${policy_file}" \
+ -i "${keyfile}" || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to seal \"${keyfile}\": ${ret}" >&2
+ return 1
+ fi
+ tpm2_flushcontext -t || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to flush the transient handles: ${ret}" >&2
+ return 1
+ fi
+
+ tpm2_load -Q \
+ -C "${primary_file}" \
+ -u "${keypub_file}" \
+ -r "${keypriv_file}" \
+ -n "${name_file}" \
+ -c "${sealing_ctx_file}" || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to load the sealed key into TPM: ${ret}" >&2
+ return 1
+ fi
+ tpm2_flushcontext -t || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to flush the transient handles: ${ret}" >&2
+ return 1
+ fi
+
+ tpm2_evictcontrol -Q -C o -c "${sealing_ctx_file}" ${nv_index} || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to store the sealed key into ${nv_index}: ${ret}" >&2
+ return 1
+ fi
+
+ return 0
+}
+
+tpm2_seal_unseal_nv() {
+ nv_index="0x81000000"
+ pcr_list="sha256:0,1"
+
+ grub_cfg=${tpm2testdir}/testcase.cfg
+
+ # Seal the key into a NV index guarded by PCR 0 and 1
+ tpm2_seal_nv "${lukskeyfile}" ${nv_index} ${pcr_list} || ret=$?
+ if [ "${ret}" -ne 0 ]; then
+ echo "Failed to seal the secret key into ${nv_index}" >&2
+ return 99
+ fi
+
+ # Write the TPM unsealing script
+ cat > ${grub_cfg} <<EOF
+loopback luks (host)${luksfile}
+tpm2_key_protector_init --mode=nv --nvindex=${nv_index} --pcrs=0,1
+if cryptomount -a --protector tpm2; then
+ cat (crypto0)+1
+fi
+EOF
+
+ # Test TPM unsealing with the same PCR
+ ${grubshell} --timeout=${timeout} --emu-opts="-t ${tpm2dev}" < "${grub_cfg}" > "${testoutput}" || ret=$?
+
+ # Remove the object from the NV index
+ tpm2_evictcontrol -Q -C o -c "${nv_index}" || :
+
+ if [ "${ret}" -eq 0 ]; then
+ if ! grep -q "^${vtext}$" "${testoutput}"; then
+ echo "error: test not verified [`cat ${testoutput}`]" >&2
+ return 1
+ fi
+ else
+ echo "grub-emu exited with error: ${ret}" >&2
+ return 99
+ fi
+}
+
+# Testcases for SRK mode
+declare -a srktests=()
+srktests+=("default transient no_fallback_srk")
+srktests+=("RSA transient no_fallback_srk")
+srktests+=("ECC transient no_fallback_srk")
+srktests+=("RSA persistent no_fallback_srk")
+srktests+=("ECC persistent no_fallback_srk")
+srktests+=("RSA transient fallback_srk")
+srktests+=("ECC transient fallback_srk")
+
+for i in "${!srktests[@]}"; do
+ tpm2_seal_unseal ${srktests[$i]} || ret=$?
+ if [ "${ret}" -eq 0 ]; then
+ echo "TPM2 [${srktests[$i]}]: PASS"
+ elif [ "${ret}" -eq 1 ]; then
+ echo "TPM2 [${srktests[$i]}]: FAIL"
+ else
+ echo "Unexpected failure [${srktests[$i]}]" >&2
+ exit ${ret}
+ fi
+done
+
+# Testcase for NV index mode
+tpm2_seal_unseal_nv || ret=$?
+if [ "${ret}" -eq 0 ]; then
+ echo "TPM2 [NV Index]: PASS"
+elif [ "${ret}" -eq 1 ]; then
+ echo "TPM2 [NV Index]: FAIL"
+else
+ echo "Unexpected failure [NV index]" >&2
+ exit ${ret}
+fi
+
+exit 0
diff --git a/tests/util/grub-shell.in b/tests/util/grub-shell.in
index ae5f711fe..15c5f45a5 100644
--- a/tests/util/grub-shell.in
+++ b/tests/util/grub-shell.in
@@ -75,6 +75,7 @@ work_directory=${WORKDIR:-`mktemp -d "${TMPDIR:-/tmp}/grub-shell.XXXXXXXXXX"`} |
. "${builddir}/grub-core/modinfo.sh"
qemuopts=
+emuopts=
serial_port=com0
serial_null=
halt_cmd=halt
@@ -376,6 +377,9 @@ for option in "$@"; do
--qemu-opts=*)
qs=`echo "$option" | sed -e 's/--qemu-opts=//'`
qemuopts="$qemuopts $qs" ;;
+ --emu-opts=*)
+ qs=`echo "$option" | sed -e 's/--emu-opts=//'`
+ emuopts="$emuopts $qs" ;;
--disk=*)
dsk=`echo "$option" | sed -e 's/--disk=//'`
if [ ${grub_modinfo_platform} = emu ]; then
@@ -674,7 +678,7 @@ elif [ x$boot = xemu ]; then
cat >"$work_directory/run.sh" <<EOF
#! @BUILD_SHEBANG@
SDIR=\$(realpath -e \${0%/*})
-exec "$(realpath -e "${builddir}")/grub-core/grub-emu" -m "\$SDIR/${device_map##*/}" --memdisk "\$SDIR/${roottar##*/}" -r memdisk -d "/boot/grub"
+exec "$(realpath -e "${builddir}")/grub-core/grub-emu" -m "\$SDIR/${device_map##*/}" --memdisk "\$SDIR/${roottar##*/}" -r memdisk -d "/boot/grub" ${emuopts}
EOF
else
cat >"$work_directory/run.sh" <<EOF
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 32/33] cryptodisk: Document the '-P' option
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (30 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 31/33] tests: Add tpm2_key_protector_test Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-10-17 18:00 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 33/33] docs: Document TPM2 key protector Gary Lin via Grub-devel
` (2 subsequent siblings)
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
The '-P' option is introduced to support the key protectors framework.
This commit adds the new option to the GRUB manual.
Signed-off-by: Gary Lin <glin@suse.com>
---
docs/grub.texi | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 2ea6c56d1..3e6f602b2 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6695,13 +6695,14 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum}
@node cryptomount
@subsection cryptomount
-@deffn Command cryptomount [ [@option{-p} password] | [@option{-k} keyfile [@option{-O} keyoffset] [@option{-S} keysize] ] ] [@option{-H} file] device|@option{-u} uuid|@option{-a}|@option{-b}
+@deffn Command cryptomount [ [@option{-p} password] | [@option{-k} keyfile [@option{-O} keyoffset] [@option{-S} keysize] ] | [@option{-P} protector] ] [@option{-H} file] device|@option{-u} uuid|@option{-a}|@option{-b}
Setup access to encrypted device. A passphrase will be requested interactively,
if neither the @option{-p} nor @option{-k} options are given. The option
@option{-p} can be used to supply a passphrase (useful for scripts).
Alternatively the @option{-k} option can be used to supply a keyfile with
options @option{-O} and @option{-S} optionally supplying the offset and size,
-respectively, of the key data in the given key file. The @option{-H} options can
+respectively, of the key data in the given key file. The @option{-P} option can
+be used to retrieve the key from a key protector. The @option{-H} options can
be used to supply cryptomount backends with an alternative header file (aka
detached header). Not all backends have headers nor support alternative header
files (currently only LUKS1 and LUKS2 support them).
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v19 33/33] docs: Document TPM2 key protector
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (31 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 32/33] cryptodisk: Document the '-P' option Gary Lin via Grub-devel
@ 2024-09-06 9:11 ` Gary Lin via Grub-devel
2024-09-13 14:25 ` Stefan Berger
2024-09-13 14:32 ` [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Stefan Berger
2024-10-03 15:58 ` Daniel Kiper
34 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-06 9:11 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
Update the user manual to address TPM2 key protector including the two
related commands, tpm2_key_protector_init and tpm2_key_protector_clear,
and the user-space utility: grub-protect.
Signed-off-by: Gary Lin <glin@suse.com>
---
docs/grub.texi | 507 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 507 insertions(+)
diff --git a/docs/grub.texi b/docs/grub.texi
index 3e6f602b2..30548ac57 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6443,6 +6443,8 @@ you forget a command, you can run the command @command{help}
* smbios:: Retrieve SMBIOS information
* source:: Read a configuration file in same context
* test:: Check file types and compare values
+* tpm2_key_protector_init:: Initialize the TPM2 key protector
+* tpm2_key_protector_clear:: Clear the TPM2 key protector
* true:: Do nothing, successfully
* trust:: Add public key to list of trusted keys
* unset:: Unset an environment variable
@@ -8000,6 +8002,56 @@ either @var{expression1} or @var{expression2} is true
@end table
@end deffn
+@node tpm2_key_protector_init
+@subsection tpm2_key_protector_init
+
+@deffn Command tpm2_key_protector_init [@option{-m} mode] | [@option{-p} pcrlist] | [@option{-b} pcrbank] | [ [@option{-T} tpm2key_file] | [@option{-k} keyfile] ] | [@option{-s} handle] | [@option{-a} srk_type] | [@option{-n} nv_index]
+Initialize the TPM2 key protector to unseal the key for the @command{cryptomount}
+(@pxref{cryptomount}) command. There are two supported mode,
+SRK(@kbd{srk}) and NV index(@kbd{nv}), to be specified by the option
+@option{-m}. The default mode is srk. The main difference between SRK mode
+and NV index mode is the storage of the sealed key. For SRK mode, the sealed
+key is stored in a file while NV index mode stores the sealed key in the
+non-volatile memory inside TPM with a given NV index.
+
+The @option{-p} and @option{-b} options are used to supply the PCR list and
+bank that the key sealed with. The PCR list is a comma-separated list, e.g.,
+'0,2,4,7,9', to represent the involved PCRs, and the default is '7'. The PCR
+bank is marked by the hash algorithms. The current supported PCR banks are
+SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
+
+There are some options only available for the specific mode. The SRK-specific
+options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
+other hand, the NV index-specific option is @option{-n}.
+
+The key file for SRK mode can be supplied with either @option{-T} or
+@option{-k}. The @option{-T} option is for the path to the key file in
+the TPM 2.0 Key File format. Since the parameters for the TPM commands are
+written in the policy sequences, there is no need to set the PCR
+list(@option{-p}) and bank(@option{-b}) when using @option{-T} option. The
+@option{-k} option is for the key file in the raw format, and the @option{-p}
+and @option{-b} options are necessary for the non-default PCR list or bank.
+
+Besides the key file, there are two options, @option{-a} and @option{-s}, to
+tweak the TPM Storage Root Key (SRK). The SRK can be either created at
+runtime or stored in the non-volatile memory. When creating SRK at runtime,
+GRUB provides the SRK template to TPM to create the key. There are two SRK
+templates, ECC and RSA, for the @option{-a} option and the default is ECC.
+If the SRK is stored in a specific handle, e.g. @code{0x81000001}, the
+@option{-s} option can be used to set the handle to notify GRUB to load
+the SRK from the given handle.
+
+The only nvindex-specific option is the option @option{-n} which is used to
+set the NV index containing the sealed key, so that GRUB can load the sealed
+key and unseal it with the given PCR list and bank.
+@end deffn
+
+@node tpm2_key_protector_clear
+@subsection tpm2_key_protector_clear
+
+@deffn Command tpm2_key_protector_clear
+Clear the TPM2 key protector if previously initialized.
+@end deffn
@node true
@subsection true
@@ -8528,6 +8580,7 @@ environment variables and commands are listed in the same order.
* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation
* Measured Boot:: Measuring boot components
* Lockdown:: Lockdown when booting on a secure setup
+* TPM2 key protector:: Managing disk key with TPM2 key protector
@end menu
@node Authentication and authorisation
@@ -8771,6 +8824,295 @@ be restricted and some operations/commands cannot be executed.
The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
Otherwise it does not exit.
+@node TPM2 key protector
+@section TPM2 key protector in GRUB
+
+TPM2 key protector extends measured boot to unlock the encrypted partition
+without user intervention. It uses the TPM Storage Root Key (SRK) to seal
+the disk key with a given set of PCR values. If the system state matches,
+i.e. PCR values match the sealed PCR set, TPM2 key protector unseals the
+disk key for @command{cryptomount} (@pxref{cryptomount}) to unlock the
+encrypted partition. (In case the unsealed key fails to unlock the
+partition, @command{cryptomount} falls back to the passphrase prompt.)
+
+There are two supported modes to store the sealed key, SRK and NV index,
+and the details will be addressed in the latter sections.
+
+TPM2 key protector is currently only supported on EFI and EMU platforms.
+
+@subsection TPM PCR usage
+
+Since TPM2 key protector relies on PCRs to check the system state, it is
+important to decide which PCRs to seal the key with. The following table
+shows the users of PCRs and the measured objects on EFI platforms.
+
+@multitable @columnfractions 0.1 0.2 0.7
+@headitem PCR @tab Used by @tab Measured Objects
+@item 0
+@tab Firmware
+@tab Core system firmware executable code
+@item 1
+@tab Firmware
+@tab Core system firmware data/host platform configuration; typically
+contains serial and model numbers
+@item 2
+@tab Firmware
+@tab Extended or pluggable executable code; includes option ROMs on
+pluggable hardware
+@item 3
+@tab Firmware
+@tab Extended or pluggable firmware data; includes information about
+pluggable hardware
+@item 4
+@tab Firmware
+@tab Boot loader and additional drivers; binaries and extensions loaded
+by the boot loader
+@item 5
+@tab Firmware
+@tab GPT/Partition table
+@item 7
+@tab Firmware
+@tab SecureBoot state
+@item 8
+@tab GRUB
+@tab Commands and kernel command line
+@item 9
+@tab GRUB
+@tab All files read (including kernel image)
+@item 9
+@tab Linux Kernel
+@tab All passed initrds (when the new LOAD_FILE2 initrd protocol is used)
+@item 10
+@tab Linux Kernel
+@tab Protection of the IMA measurement log
+@item 14
+@tab shim
+@tab “MOK” certificates and hashes
+@end multitable
+
+PCR 0, 2, 4, and 7 can be used to check the integrity of the firmware code
+and bootloaders. PCR 8 and 9 are useful to check the file and data processed
+by GRUB. PCRs 10, 11, 12, 13, and 15 are controlled by the operating system,
+so those PCRs are usually still in the initial state when GRUB is running.
+
+In general, it is nice to include PCR 0, 2, 4, and 7 to ensure the integrity
+of the firmware and bootloaders. For PCR 8 and 9, a sophisticated tool is
+required to examine the GRUB configuration files and the files to be loaded
+to calculate the correct PCR values.
+
+Please note that PCRs are sensitive to any change, so an update of a component
+could invalidate the sealed key, and it is so-called PCR brittleness. For the
+bootloader update, PCR 4 may be affected. This can be mitigated by extracting
+the events from the TPM event log and predict the value with the updated
+bootloader binary. On the other hand, it is difficult to predict PCR 0~7 after
+a firmware update since the content of the code and the order of drivers may
+not follow the TPM event log from the previous firmware version, so it is
+necessary to reboot the system to update the measurement results of PCR 0~7
+and seal or sign the sealed key again.
+
+Reference: @url{https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/, Linux TPM PCR Registry}
+
+@subsection Setting up the extra disk key
+
+Instead of using the existing password, it is recommended to seal a new
+random disk key and use the existing password for recovery.
+
+Here are the sample commands to create a 128 random bytes key file and
+enroll the key into the target partition (sda2).
+
+@example
+# @kbd{dd if=/dev/urandom of=luks.key bs=1 count=128}
+# @kbd{cryptsetup luksAddKey /dev/sda2 luks.key --pbkdf=pbkdf2 --hash=sha512}
+@end example
+
+@subsection SRK mode
+
+To unlock the partition with SRK mode, assume that the sealed key is in
+@file{(hd0,gpt1)/boot/grub2/sealed.tpm}, the following GRUB commands
+unseal the disk key with SRK mode and supply it to @command{cryptomount}.
+
+@example
+@kbd{tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
+@kbd{cryptomount -u <UUID> -P tpm2}
+@end example
+
+There are two programs to create the sealed key for SRK mode: @command{grub-protect}
+and @command{pcr-oracle} (@url{https://github.com/okirch/pcr-oracle}).
+
+The following sample command uses @command{grub-protect} to seal the random
+key, @file{luks.key}, with PCR 0, 2, 4 and 7 in TPM 2.0 Key File format.
+
+@example
+@group
+# @kbd{grub-protect --action=add \
+ --protector=tpm2 \
+ --tpm2-pcrs=0,2,4,7 \
+ --tpm2key \
+ --tpm2-keyfile=luks.key \
+ --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
+@end group
+@end example
+
+Since @command{grub-protect} only seals the key with the current PCR values,
+when a boot component updates such as shim or GRUB, it requires to reboot the
+system to update the measurement results and seal the key again. That means
+the random disk key has to be stored in cleartext for the next key sealing.
+Besides, the measurement result of some PCRs may differ between boot time and
+OS runtime. For example, PCR 9 measures the files loaded by GRUB including the
+linux kernel and initrd. To unlock the disk containing the kernel and initrd,
+the key has to be sealed with PCR 9 value before loading the kernel and
+initrd. However, PCR 9 changes after GRUB loading the kernel and initrd, so
+PCR 9 at OS runtime cannot be used directly for key sealing.
+
+To solve the problems, @command{pcr-oracle} takes a different approach. It
+reads the TPM eventlog and predicts the PCR values. Besides,
+@command{pcr-oracle} also supports ``authorized policy'' which allows the
+PCR policy to be updated with a valid signature, so that the user only
+needs to seal the random disk key once and then updates the signature
+of PCR policy for the later changes.
+
+To seal the key with authorized policy, the first thing is to generate
+the RSA policy key, @file{policy-key.pem}, and the authorized policy file,
+@file{authorized.policy}. In this example, PCR 0, 2, 4, 7 and 9 are chosen
+for key sealing.
+
+@example
+@group
+# @kbd{pcr-oracle --rsa-generate-key \
+ --private-key policy-key.pem \
+ --auth authorized.policy \
+ create-authorized-policy 0,2,4,7,9}
+@end group
+@end example
+
+Then, we seal the random disk key, @file{luks.key}, with the authorized
+policy file and save the sealed key in @file{sealed.key}.
+
+@example
+@group
+# @kbd{pcr-oracle --key-format tpm2.0 \
+ --auth authorized.policy \
+ --input luks.key \
+ --output sealed.key \
+ seal-secret}
+@end group
+@end example
+
+The random disk key file, @file{luks.key}, now can be removed for good.
+The last step is to sign the predicted PCR policy and save the final key
+file, @file{sealed.tpm}.
+
+@example
+@group
+# @kbd{pcr-oracle --key-format tpm2.0 \
+ --private-key policy-key.pem \
+ --from eventlog \
+ --stop-event "grub-file=grub.cfg" \
+ --after \
+ --input sealed.key \
+ --output /boot/efi/boot/grub2/sealed.tpm \
+ sign 0,2,4,7,9}
+@end group
+@end example
+
+Here we also set a stop event for the prediction. With
+@kbd{--stop-event grub-file=grub.cfg --after}, @command{pcr-oracle} stops
+the calculation of PCR values right after GRUB loads @file{grub.cfg}.
+
+When shim or GRUB updates, it only requires to run the last @command{pcr-oracle}
+command to update the predicted PCR policy.
+
+@subsection NV index mode
+
+Instead of storing the sealed key in the file, NV index mode uses the TPM
+non-volatile memory for the sealed key.
+
+The following sample commands use tpm2-tools (@url{https://github.com/tpm2-software/tpm2-tools})
+commands to seal @file{luks.key} into the specific NV index: @kbd{0x81000000}.
+
+First, we need to create the object file for the primary key, i.e. storage
+root key (SRK) with the default key settings in GRUB: SHA256 hash algorithm
+and ECC key algorithm.
+
+@example
+# @kbd{tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx}
+@end example
+
+The next commands collect the current values of PCR 0, 2, 4, and 7 and saves
+them in @file{pcr.dat}.
+
+@example
+# @kbd{tpm2_startauthsession -S session.dat}
+# @kbd{tpm2_policypcr -S session.dat -l sha256:0,2,4,7 -f pcrs.dat -L policy.dat}
+# @kbd{tpm2_flushcontext session.dat}
+@end example
+
+The last commands seal @file{luks.key} with the primary key and stores the
+result in @kbd{0x81000000}.
+
+@example
+# @kbd{cat luks.key | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-}
+# @kbd{tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx}
+# @kbd{tpm2_evictcontrol -C o -c sealing.ctx 0x81000000}
+@end example
+
+To unseal the key, we have to specify the mode, @kbd{nv}, the NV index,
+@kbd{0x81000000}, and the PCRs, @kbd{0,2,4,7} for @command{tpm2_key_protector_init}
+command.
+
+@example
+@kbd{tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=0,2,4,7}
+@kbd{cryptomount -u <UUID> --protector tpm2}
+@end example
+
+@subsection Setting up software TPM for EMU platform
+
+In order to test TPM2 key protector and TPM2 Software Stack (TSS2), it is
+handy to set up a software TPM (swtpm) instance and run the commands on the
+EMU platform.
+
+Here are the commands to start a swtpm instance which provides a character
+device interface. To store the TPM states, the directory, @file{swtpm-state},
+is created before the @command{swtpm} command. All the messages are stored
+in @file{swtpm.log} including the name of the character device.
+
+@example
+# @kbd{mkdir swtpm-state}
+@group
+# @kbd{swtpm chardev --vtpm-proxy --tpmstate dir=swtpm-state \
+ --tpm2 --ctrl type=unixio,path="swtpm-state/ctrl" \
+ --flags startup-clear --daemon > swtpm.log}
+@end group
+@end example
+
+Then, we extract the name of the character device from @file{swtpm.log} and
+save it to the variable, @samp{tpm2dev}.
+
+@example
+# @kbd{tpm2dev=$(grep "New TPM device" swtpm.log | cut -d' ' -f 4)}
+@end example
+
+Now we can start @kbd{grub-emu} with @kbd{--tpm-device $tpm2dev} to interact
+with the swtpm instance.
+
+@example
+# @kbd{grub-emu --tpm-device $tpm2dev}
+@end example
+
+On the host, the tpm2-tools commands can interact with the swtpm instance by
+setting @samp{TPM2TOOLS_TCTI}.
+
+@example
+# @kbd{export TPM2TOOLS_TCTI="device:$tpm2dev"}
+@end example
+
+When the test is done, use @kbd{swtpm_ioctl} to send the shutdown
+command through the swtpm control channel.
+
+@example
+# @kbd{swtpm_ioctl -s --unix swtpm-state/ctrl}
+@end example
+
@node Platform limitations
@chapter Platform limitations
@@ -9211,6 +9553,7 @@ bootability on other machines.
* Invoking grub-mkrescue:: Make a GRUB rescue image
* Invoking grub-mount:: Mount a file system using GRUB
* Invoking grub-probe:: Probe device information for GRUB
+* Invoking grub-protect:: Protect a disk key with a key protector
* Invoking grub-script-check:: Check GRUB script file for syntax errors
@end menu
@@ -9593,6 +9936,170 @@ Print verbose messages.
@end table
+@node Invoking grub-protect
+@section Invoking grub-protect
+
+The program @command{grub-protect} protects a disk encryption key with
+a specified key protector.
+
+@table @option
+@item --help
+Print a summary of the command-line options and exit.
+
+@item --version
+Print the version number of GRUB and exit.
+
+@item -a
+@itemx --action=add|remove
+Add or remove a key protector to or from a key.
+
+@item -p
+@itemx --protector=@var{protector}
+Set the key protector. Currently, @samp{tpm2} is the only supported key
+protector.
+
+@item --tpm2-asymmetric=@var{type}
+Choose the the type of SRK. The valid options are @samp{RSA} (@samp{RSA2048})
+and @samp{ECC} (@samp{ECC_NIST_P256}).(default: @samp{ECC})
+
+@item --tpm2-bank=@var{alg}
+Choose bank of PCRs used to authorize key release: @samp{SHA1}, @samp{SHA256},
+@samp{SHA384}, or @samp{SHA512}. (default: @samp{SHA256})
+
+@item --tpm2-device=@var{device}
+Set the path to the TPM2 device. (default: @samp{/dev/tpm0})
+
+@item --tpm2-evict
+Evict a previously persisted SRK from the TPM, if any.
+
+@item --tpm2-keyfile=@var{file}
+Set the path to a file that contains the cleartext key to protect.
+
+@item --tpm2-outfile=@var{file}
+Set the path to the file that will contain the key after sealing
+(must be accessible to GRUB during boot).
+
+@item --tpm2-pcrs=@var{pcrs}
+Set a comma-separated list of PCRs used to authorize key release e.g., @samp{7,11}.
+Please be aware that PCR 0~7 are used by the firmware and the measurement result
+may change after a firmware update (for baremetal systems) or a package
+(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to the failure of key
+unsealing. (default: @samp{7})
+
+@item --tpm2-srk=@var{handle}
+Set the SRK handle, e.g. @samp{0x81000000}, if the SRK is to be made persistent.
+
+@item --tpm2key
+Use TPM 2.0 Key File format instead of the raw format.
+
+@end table
+
+Before sealing the key, please check the TPM PCR usage
+(@pxref{TPM2 key protector, TPM PCR usage}) to choose a proper set of PCRs.
+
+Assume that there is a key file, @file{luks.key}, to be sealed with PCR 0, 2,
+4, and 7, here is the @command{grub-protect} command to create the sealed
+key file:
+
+@example
+@group
+# @kbd{grub-protect --action=add \
+ --protector=tpm2 \
+ --tpm2-pcrs=0,2,4,7 \
+ --tpm2key \
+ --tpm2-keyfile=luks.key \
+ --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
+@end group
+@end example
+
+Then, GRUB can unlock the target partition with the following commands:
+
+@example
+@kbd{tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
+@kbd{cryptomount -u <UUID> -P tpm2}
+@end example
+
+In most of cases, the user only needs to create the key with the `add' action.
+If auto-unlocking is unwanted, just remove the file and restore the GRUB
+commands.
+
+The only case for the `remove' action is when the SRK is made persistent.
+
+There are two supported SRKs in @command{grub-protect}: @samp{RSA} and @samp{ECC}.
+Due to slower key generation, some users of the @samp{RSA} SRK would prefer
+making it persistent so that the TPM can skip the SRK generation when GRUB tries
+to unseal the key.
+
+The available persistent handles can be checked with @command{tpm2_getcap}.
+
+@example
+@group
+# @kbd{tpm2_getcap properties-variable}
+...
+TPM2_PT_HR_PERSISTENT: 0x0
+TPM2_PT_HR_PERSISTENT_AVAIL: 0x41
+...
+@end group
+@end example
+
+In this system, there is no persistent handle. A TPM handle is an unsigned
+32-bit integer, and the persistent handles starts with @samp{0x81}. Here
+we choose the well-known persistent handle: @samp{0x81000000}.
+
+@example
+@group
+# @kbd{grub-protect --action=add \
+ --protector=tpm2 \
+ --tpm2-pcrs=0,2,4,7 \
+ --tpm2-asymmetric=RSA \
+ --tpm2-srk=0x81000000 \
+ --tpm2key \
+ --tpm2-keyfile=luks.key \
+ --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
+@end group
+@end example
+
+The additional @kbd{--tpm2-asymmetric=RSA} and @kbd{--tpm2-srk=0x81000000}
+options are used to make the key sealed with the RSA SRK and store the SRK
+in @samp{0x81000000}.
+
+For the @command{tpm2_key_protector_init} command, the additional @kbd{-s 0x81000000}
+informs the TPM2 key protector to fetch the SRK from @samp{0x81000000}.
+
+@example
+@kbd{tpm2_key_protector_init -s 0x81000000 --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
+@kbd{cryptomount -u <UUID> -P tpm2}
+@end example
+
+After making the SRK handle persistent, we can check the status of the
+persistent handles with @command{tpm2_getcap}.
+
+@example
+@group
+# @kbd{tpm2_getcap properties-variable}
+...
+TPM2_PT_HR_PERSISTENT: 0x1
+TPM2_PT_HR_PERSISTENT_AVAIL: 0x40
+...
+# @kbd{tpm2_getcap handles-persistent}
+- 0x81000000
+@end group
+@end example
+
+In case the user doesn't want to use the TPM2 key protector anymore, besides
+removing the sealed key file, here is the command to remove the persistent
+SRK handle (@samp{0x81000000}.) with @kbd{--tpm2-srk} and @kbd{--tpm2-evict}.
+
+@example
+@group
+# @kbd{grub-protect --action=remove \
+ --protector=tpm2 \
+ --tpm2-srk 0x81000000 \
+ --tpm2-evict}
+@end group
+@end example
+
+
@node Invoking grub-script-check
@section Invoking grub-script-check
--
2.35.3
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* Re: [PATCH v19 33/33] docs: Document TPM2 key protector
2024-09-06 9:11 ` [PATCH v19 33/33] docs: Document TPM2 key protector Gary Lin via Grub-devel
@ 2024-09-13 14:25 ` Stefan Berger
2024-09-20 8:16 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-13 14:25 UTC (permalink / raw)
To: Gary Lin, The development of GNU GRUB
Cc: Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On 9/6/24 5:11 AM, Gary Lin wrote:
> Update the user manual to address TPM2 key protector including the two
> related commands, tpm2_key_protector_init and tpm2_key_protector_clear,
> and the user-space utility: grub-protect.
>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
> docs/grub.texi | 507 +++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 507 insertions(+)
>
> diff --git a/docs/grub.texi b/docs/grub.texi
> index 3e6f602b2..30548ac57 100644
> --- a/docs/grub.texi
> +++ b/docs/grub.texi
> @@ -6443,6 +6443,8 @@ you forget a command, you can run the command @command{help}
> * smbios:: Retrieve SMBIOS information
> * source:: Read a configuration file in same context
> * test:: Check file types and compare values
> +* tpm2_key_protector_init:: Initialize the TPM2 key protector
> +* tpm2_key_protector_clear:: Clear the TPM2 key protector
> * true:: Do nothing, successfully
> * trust:: Add public key to list of trusted keys
> * unset:: Unset an environment variable
> @@ -8000,6 +8002,56 @@ either @var{expression1} or @var{expression2} is true
> @end table
> @end deffn
>
> +@node tpm2_key_protector_init
> +@subsection tpm2_key_protector_init
> +
> +@deffn Command tpm2_key_protector_init [@option{-m} mode] | [@option{-p} pcrlist] | [@option{-b} pcrbank] | [ [@option{-T} tpm2key_file] | [@option{-k} keyfile] ] | [@option{-s} handle] | [@option{-a} srk_type] | [@option{-n} nv_index]
> +Initialize the TPM2 key protector to unseal the key for the @command{cryptomount}
> +(@pxref{cryptomount}) command. There are two supported mode,
s/mode/modes
> +SRK(@kbd{srk}) and NV index(@kbd{nv}), to be specified by the option
> +@option{-m}. The default mode is srk. The main difference between SRK mode
s/srk/SRK
> +and NV index mode is the storage of the sealed key. For SRK mode, the sealed
> +key is stored in a file while NV index mode stores the sealed key in the
> +non-volatile memory inside TPM with a given NV index.
> +
> +The @option{-p} and @option{-b} options are used to supply the PCR list and
> +bank that the key sealed with. The PCR list is a comma-separated list, e.g.,
key is sealed with (?)
> +'0,2,4,7,9', to represent the involved PCRs, and the default is '7'. The PCR
> +bank is marked by the hash algorithms. The current supported PCR banks are
bank is chosen by selecting a hash algorithm (?)
> +SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
> +
> +There are some options only available for the specific mode. The SRK-specific
> +options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
> +other hand, the NV index-specific option is @option{-n}.
> +
> +The key file for SRK mode can be supplied with either @option{-T} or
> +@option{-k}. The @option{-T} option is for the path to the key file in
> +the TPM 2.0 Key File format. Since the parameters for the TPM commands are
> +written in the policy sequences, there is no need to set the PCR
What is 'the policy sequences' ?
> +list(@option{-p}) and bank(@option{-b}) when using @option{-T} option. The
the @option{-T} option
> +@option{-k} option is for the key file in the raw format, and the @option{-p}
> +and @option{-b} options are necessary for the non-default PCR list or bank.
> +
> +Besides the key file, there are two options, @option{-a} and @option{-s}, to
> +tweak the TPM Storage Root Key (SRK). The SRK can be either created at
> +runtime or stored in the non-volatile memory. When creating SRK at runtime,
> +GRUB provides the SRK template to TPM to create the key. There are two SRK
> +templates, ECC and RSA, for the @option{-a} option and the default is ECC.
> +If the SRK is stored in a specific handle, e.g. @code{0x81000001}, the
> +@option{-s} option can be used to set the handle to notify GRUB to load
> +the SRK from the given handle.
> +
> +The only nvindex-specific option is the option @option{-n} which is used to
> +set the NV index containing the sealed key, so that GRUB can load the sealed
> +key and unseal it with the given PCR list and bank.
> +@end deffn
> +
> +@node tpm2_key_protector_clear
> +@subsection tpm2_key_protector_clear
> +
> +@deffn Command tpm2_key_protector_clear
> +Clear the TPM2 key protector if previously initialized.
> +@end deffn
>
> @node true
> @subsection true
> @@ -8528,6 +8580,7 @@ environment variables and commands are listed in the same order.
> * Secure Boot Advanced Targeting:: Embedded information for generation number based revocation
> * Measured Boot:: Measuring boot components
> * Lockdown:: Lockdown when booting on a secure setup
> +* TPM2 key protector:: Managing disk key with TPM2 key protector
> @end menu
>
> @node Authentication and authorisation
> @@ -8771,6 +8824,295 @@ be restricted and some operations/commands cannot be executed.
> The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
> Otherwise it does not exit.
>
> +@node TPM2 key protector
> +@section TPM2 key protector in GRUB
> +
> +TPM2 key protector extends measured boot to unlock the encrypted partition
> +without user intervention. It uses the TPM Storage Root Key (SRK) to seal
> +the disk key with a given set of PCR values. If the system state matches,
> +i.e. PCR values match the sealed PCR set, TPM2 key protector unseals the
> +disk key for @command{cryptomount} (@pxref{cryptomount}) to unlock the
> +encrypted partition. (In case the unsealed key fails to unlock the
> +partition, @command{cryptomount} falls back to the passphrase prompt.)
> +
> +There are two supported modes to store the sealed key, SRK and NV index,
> +and the details will be addressed in the latter sections.
s/in the latter sections/in later sections?
> +
> +TPM2 key protector is currently only supported on EFI and EMU platforms.
When I looked through the patches I did not see anything particularly
related to EFI. Is it only available on EFI and EMU platforms because
you did not test it with a (Sea)BIOS for example ? I was actually going
to try it on PPC64 on KVM that has SLOF firmware.
> +
> +@subsection TPM PCR usage
> +
> +Since TPM2 key protector relies on PCRs to check the system state, it is
> +important to decide which PCRs to seal the key with. The following table
> +shows the users of PCRs and the measured objects on EFI platforms.
> +
> +@multitable @columnfractions 0.1 0.2 0.7
> +@headitem PCR @tab Used by @tab Measured Objects
> +@item 0
> +@tab Firmware
> +@tab Core system firmware executable code
> +@item 1
> +@tab Firmware
> +@tab Core system firmware data/host platform configuration; typically
> +contains serial and model numbers
> +@item 2
> +@tab Firmware
> +@tab Extended or pluggable executable code; includes option ROMs on
> +pluggable hardware
> +@item 3
> +@tab Firmware
> +@tab Extended or pluggable firmware data; includes information about
> +pluggable hardware
> +@item 4
> +@tab Firmware
> +@tab Boot loader and additional drivers; binaries and extensions loaded
> +by the boot loader
> +@item 5
> +@tab Firmware
> +@tab GPT/Partition table
> +@item 7
> +@tab Firmware
> +@tab SecureBoot state
> +@item 8
> +@tab GRUB
> +@tab Commands and kernel command line
> +@item 9
> +@tab GRUB
> +@tab All files read (including kernel image)
> +@item 9
> +@tab Linux Kernel
> +@tab All passed initrds (when the new LOAD_FILE2 initrd protocol is used)
> +@item 10
> +@tab Linux Kernel
> +@tab Protection of the IMA measurement log
> +@item 14
> +@tab shim
> +@tab “MOK” certificates and hashes
> +@end multitable
> +
> +PCR 0, 2, 4, and 7 can be used to check the integrity of the firmware code
> +and bootloaders. PCR 8 and 9 are useful to check the file and data processed
> +by GRUB. PCRs 10, 11, 12, 13, and 15 are controlled by the operating system,
> +so those PCRs are usually still in the initial state when GRUB is running.
> +
> +In general, it is nice to include PCR 0, 2, 4, and 7 to ensure the integrity
> +of the firmware and bootloaders. For PCR 8 and 9, a sophisticated tool is
> +required to examine the GRUB configuration files and the files to be loaded
> +to calculate the correct PCR values.
> +
> +Please note that PCRs are sensitive to any change, so an update of a component
> +could invalidate the sealed key, and it is so-called PCR brittleness. For the
, due to the so-called ..
> +bootloader update, PCR 4 may be affected. This can be mitigated by extracting
> +the events from the TPM event log and predict the value with the updated
> +bootloader binary. On the other hand, it is difficult to predict PCR 0~7 after
> +a firmware update since the content of the code and the order of drivers may
> +not follow the TPM event log from the previous firmware version, so it is
> +necessary to reboot the system to update the measurement results of PCR 0~7
> +and seal or sign the sealed key again.
> +
> +Reference: @url{https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/, Linux TPM PCR Registry}
> +
> +@subsection Setting up the extra disk key
> +
> +Instead of using the existing password, it is recommended to seal a new
> +random disk key and use the existing password for recovery.
> +
> +Here are the sample commands to create a 128 random bytes key file and
> +enroll the key into the target partition (sda2).
> +
> +@example
> +# @kbd{dd if=/dev/urandom of=luks.key bs=1 count=128}
> +# @kbd{cryptsetup luksAddKey /dev/sda2 luks.key --pbkdf=pbkdf2 --hash=sha512}
> +@end example
> +
> +@subsection SRK mode
> +
> +To unlock the partition with SRK mode, assume that the sealed key is in
> +@file{(hd0,gpt1)/boot/grub2/sealed.tpm}, the following GRUB commands
> +unseal the disk key with SRK mode and supply it to @command{cryptomount}.
> +
> +@example
> +@kbd{tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
> +@kbd{cryptomount -u <UUID> -P tpm2}
> +@end example
> +
> +There are two programs to create the sealed key for SRK mode: @command{grub-protect}
> +and @command{pcr-oracle} (@url{https://github.com/okirch/pcr-oracle}).
> +
> +The following sample command uses @command{grub-protect} to seal the random
> +key, @file{luks.key}, with PCR 0, 2, 4 and 7 in TPM 2.0 Key File format.
> +
> +@example
> +@group
> +# @kbd{grub-protect --action=add \
> + --protector=tpm2 \
> + --tpm2-pcrs=0,2,4,7 \
> + --tpm2key \
> + --tpm2-keyfile=luks.key \
> + --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
> +@end group
> +@end example
> +
> +Since @command{grub-protect} only seals the key with the current PCR values,
> +when a boot component updates such as shim or GRUB, it requires to reboot the
@command{grub-protect} only seals the key with the current PCR values.
Therefore, when a boot component, such as shim or GRUB, are updated, it
is neccessary to reboot the system to update the measurement results and
seal the key again.
> +system to update the measurement results and seal the key again. That means
> +the random disk key has to be stored in cleartext for the next key sealing.
> +Besides, the measurement result of some PCRs may differ between boot time and
Besides this, ...
> +OS runtime. For example, PCR 9 measures the files loaded by GRUB including the
> +linux kernel and initrd. To unlock the disk containing the kernel and initrd,
s/linux/Linux
> +the key has to be sealed with PCR 9 value before loading the kernel and
> +initrd. However, PCR 9 changes after GRUB loading the kernel and initrd, so
> +PCR 9 at OS runtime cannot be used directly for key sealing.
> +
> +To solve the problems, @command{pcr-oracle} takes a different approach. It
s/the/these/
> +reads the TPM eventlog and predicts the PCR values. Besides,
> +@command{pcr-oracle} also supports ``authorized policy'' which allows the
> +PCR policy to be updated with a valid signature, so that the user only
> +needs to seal the random disk key once and then updates the signature
> +of PCR policy for the later changes.
... and then the user needs to update the signature of the PCR policy
for the later changes. (?)
I am not sure what this means though in practice.
> +
> +To seal the key with authorized policy, the first thing is to generate
the authorized policyt
> +the RSA policy key, @file{policy-key.pem}, and the authorized policy file,
> +@file{authorized.policy}. In this example, PCR 0, 2, 4, 7 and 9 are chosen
> +for key sealing.
> +
> +@example
> +@group
> +# @kbd{pcr-oracle --rsa-generate-key \
> + --private-key policy-key.pem \
> + --auth authorized.policy \
> + create-authorized-policy 0,2,4,7,9}
> +@end group
> +@end example
> +
> +Then, we seal the random disk key, @file{luks.key}, with the authorized
> +policy file and save the sealed key in @file{sealed.key}.
> +
> +@example
> +@group
> +# @kbd{pcr-oracle --key-format tpm2.0 \
> + --auth authorized.policy \
> + --input luks.key \
> + --output sealed.key \
> + seal-secret}
> +@end group
> +@end example
> +
> +The random disk key file, @file{luks.key}, now can be removed for good.
Since we now have the sealed key we can now remove the random disk key
file @file{lukes.key}.
> +The last step is to sign the predicted PCR policy and save the final key
> +file, @file{sealed.tpm}.
> +
> +@example
> +@group
> +# @kbd{pcr-oracle --key-format tpm2.0 \
> + --private-key policy-key.pem \
> + --from eventlog \
> + --stop-event "grub-file=grub.cfg" \
> + --after \
> + --input sealed.key \
> + --output /boot/efi/boot/grub2/sealed.tpm \
> + sign 0,2,4,7,9}
> +@end group
> +@end example
> +
> +Here we also set a stop event for the prediction. With
> +@kbd{--stop-event grub-file=grub.cfg --after}, @command{pcr-oracle} stops
> +the calculation of PCR values right after GRUB loads @file{grub.cfg}.
> +
> +When shim or GRUB updates, it only requires to run the last @command{pcr-oracle}
> +command to update the predicted PCR policy.
> +
> +@subsection NV index mode
> +
> +Instead of storing the sealed key in the file, NV index mode uses the TPM
in a file
> +non-volatile memory for the sealed key.
to store the sealed key
> +
> +The following sample commands use tpm2-tools (@url{https://github.com/tpm2-software/tpm2-tools})
> +commands to seal @file{luks.key} into the specific NV index: @kbd{0x81000000}.
> +
> +First, we need to create the object file for the primary key, i.e. storage
> +root key (SRK) with the default key settings in GRUB: SHA256 hash algorithm
> +and ECC key algorithm.
> +
> +@example
> +# @kbd{tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx}
> +@end example
> +
> +The next commands collect the current values of PCR 0, 2, 4, and 7 and saves
> +them in @file{pcr.dat}.
> +
> +@example
> +# @kbd{tpm2_startauthsession -S session.dat}
> +# @kbd{tpm2_policypcr -S session.dat -l sha256:0,2,4,7 -f pcrs.dat -L policy.dat}
> +# @kbd{tpm2_flushcontext session.dat}
> +@end example
> +
> +The last commands seal @file{luks.key} with the primary key and stores the
> +result in @kbd{0x81000000}.
> +
> +@example
> +# @kbd{cat luks.key | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-}
> +# @kbd{tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx}
> +# @kbd{tpm2_evictcontrol -C o -c sealing.ctx 0x81000000}
> +@end example
> +
> +To unseal the key, we have to specify the mode, @kbd{nv}, the NV index,
> +@kbd{0x81000000}, and the PCRs, @kbd{0,2,4,7} for @command{tpm2_key_protector_init}
> +command.
> +
> +@example
> +@kbd{tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=0,2,4,7}
> +@kbd{cryptomount -u <UUID> --protector tpm2}
> +@end example
> +
> +@subsection Setting up software TPM for EMU platform
> +
> +In order to test TPM2 key protector and TPM2 Software Stack (TSS2), it is
> +handy to set up a software TPM (swtpm) instance and run the commands on the
> +EMU platform.
> +
> +Here are the commands to start a swtpm instance which provides a character
> +device interface. To store the TPM states, the directory, @file{swtpm-state},
> +is created before the @command{swtpm} command. All the messages are stored
> +in @file{swtpm.log} including the name of the character device.
> +
> +@example
> +# @kbd{mkdir swtpm-state}
> +@group
> +# @kbd{swtpm chardev --vtpm-proxy --tpmstate dir=swtpm-state \
> + --tpm2 --ctrl type=unixio,path="swtpm-state/ctrl" \
> + --flags startup-clear --daemon > swtpm.log}
> +@end group
> +@end example
> +
> +Then, we extract the name of the character device from @file{swtpm.log} and
> +save it to the variable, @samp{tpm2dev}.
> +
> +@example
> +# @kbd{tpm2dev=$(grep "New TPM device" swtpm.log | cut -d' ' -f 4)}
> +@end example
> +
> +Now we can start @kbd{grub-emu} with @kbd{--tpm-device $tpm2dev} to interact
> +with the swtpm instance.
> +
> +@example
> +# @kbd{grub-emu --tpm-device $tpm2dev}
> +@end example
> +
> +On the host, the tpm2-tools commands can interact with the swtpm instance by
> +setting @samp{TPM2TOOLS_TCTI}.
> +
> +@example
> +# @kbd{export TPM2TOOLS_TCTI="device:$tpm2dev"}
> +@end example
> +
> +When the test is done, use @kbd{swtpm_ioctl} to send the shutdown
> +command through the swtpm control channel.
> +
> +@example
> +# @kbd{swtpm_ioctl -s --unix swtpm-state/ctrl}
> +@end example
> +
> @node Platform limitations
> @chapter Platform limitations
>
> @@ -9211,6 +9553,7 @@ bootability on other machines.
> * Invoking grub-mkrescue:: Make a GRUB rescue image
> * Invoking grub-mount:: Mount a file system using GRUB
> * Invoking grub-probe:: Probe device information for GRUB
> +* Invoking grub-protect:: Protect a disk key with a key protector
> * Invoking grub-script-check:: Check GRUB script file for syntax errors
> @end menu
>
> @@ -9593,6 +9936,170 @@ Print verbose messages.
> @end table
>
>
> +@node Invoking grub-protect
> +@section Invoking grub-protect
> +
> +The program @command{grub-protect} protects a disk encryption key with
> +a specified key protector.
> +
> +@table @option
> +@item --help
> +Print a summary of the command-line options and exit.
> +
> +@item --version
> +Print the version number of GRUB and exit.
> +
> +@item -a
> +@itemx --action=add|remove
> +Add or remove a key protector to or from a key.
> +
> +@item -p
> +@itemx --protector=@var{protector}
> +Set the key protector. Currently, @samp{tpm2} is the only supported key
> +protector.
> +
> +@item --tpm2-asymmetric=@var{type}
> +Choose the the type of SRK. The valid options are @samp{RSA} (@samp{RSA2048})
> +and @samp{ECC} (@samp{ECC_NIST_P256}).(default: @samp{ECC})
> +
> +@item --tpm2-bank=@var{alg}
> +Choose bank of PCRs used to authorize key release: @samp{SHA1}, @samp{SHA256},
> +@samp{SHA384}, or @samp{SHA512}. (default: @samp{SHA256})
> +
> +@item --tpm2-device=@var{device}
> +Set the path to the TPM2 device. (default: @samp{/dev/tpm0})
> +
> +@item --tpm2-evict
> +Evict a previously persisted SRK from the TPM, if any.
> +
> +@item --tpm2-keyfile=@var{file}
> +Set the path to a file that contains the cleartext key to protect.
> +
> +@item --tpm2-outfile=@var{file}
> +Set the path to the file that will contain the key after sealing
> +(must be accessible to GRUB during boot).
> +
> +@item --tpm2-pcrs=@var{pcrs}
> +Set a comma-separated list of PCRs used to authorize key release e.g., @samp{7,11}.
> +Please be aware that PCR 0~7 are used by the firmware and the measurement result
> +may change after a firmware update (for baremetal systems) or a package
> +(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to the failure of key
> +unsealing. (default: @samp{7})
> +
> +@item --tpm2-srk=@var{handle}
> +Set the SRK handle, e.g. @samp{0x81000000}, if the SRK is to be made persistent.
> +
> +@item --tpm2key
> +Use TPM 2.0 Key File format instead of the raw format.
TPM 2.0 key file (?)
> +
> +@end table
> +
> +Before sealing the key, please check the TPM PCR usage
> +(@pxref{TPM2 key protector, TPM PCR usage}) to choose a proper set of PCRs.
> +
> +Assume that there is a key file, @file{luks.key}, to be sealed with PCR 0, 2,
> +4, and 7, here is the @command{grub-protect} command to create the sealed
, then here ...
> +key file:
> +
> +@example
> +@group
> +# @kbd{grub-protect --action=add \
> + --protector=tpm2 \
> + --tpm2-pcrs=0,2,4,7 \
> + --tpm2key \
> + --tpm2-keyfile=luks.key \
> + --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
> +@end group
> +@end example
> +
> +Then, GRUB can unlock the target partition with the following commands:
> +
> +@example
> +@kbd{tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
> +@kbd{cryptomount -u <UUID> -P tpm2}
> +@end example
> +
> +In most of cases, the user only needs to create the key with the `add' action.
> +If auto-unlocking is unwanted, just remove the file and restore the GRUB
> +commands.
> +
> +The only case for the `remove' action is when the SRK is made persistent.
> +
> +There are two supported SRKs in @command{grub-protect}: @samp{RSA} and @samp{ECC}.
> +Due to slower key generation, some users of the @samp{RSA} SRK would prefer
> +making it persistent so that the TPM can skip the SRK generation when GRUB tries
> +to unseal the key.
> +
> +The available persistent handles can be checked with @command{tpm2_getcap}.
> +
> +@example
> +@group
> +# @kbd{tpm2_getcap properties-variable}
> +...
> +TPM2_PT_HR_PERSISTENT: 0x0
> +TPM2_PT_HR_PERSISTENT_AVAIL: 0x41
> +...
> +@end group
> +@end example
> +
> +In this system, there is no persistent handle. A TPM handle is an unsigned
> +32-bit integer, and the persistent handles starts with @samp{0x81}. Here
> +we choose the well-known persistent handle: @samp{0x81000000}.
> +
> +@example
> +@group
> +# @kbd{grub-protect --action=add \
> + --protector=tpm2 \
> + --tpm2-pcrs=0,2,4,7 \
> + --tpm2-asymmetric=RSA \
> + --tpm2-srk=0x81000000 \
> + --tpm2key \
> + --tpm2-keyfile=luks.key \
> + --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
> +@end group
> +@end example
> +
> +The additional @kbd{--tpm2-asymmetric=RSA} and @kbd{--tpm2-srk=0x81000000}
> +options are used to make the key sealed with the RSA SRK and store the SRK
> +in @samp{0x81000000}.
> +
> +For the @command{tpm2_key_protector_init} command, the additional @kbd{-s 0x81000000}
> +informs the TPM2 key protector to fetch the SRK from @samp{0x81000000}.
> +
> +@example
> +@kbd{tpm2_key_protector_init -s 0x81000000 --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
> +@kbd{cryptomount -u <UUID> -P tpm2}
> +@end example
> +
> +After making the SRK handle persistent, we can check the status of the
> +persistent handles with @command{tpm2_getcap}.
> +
> +@example
> +@group
> +# @kbd{tpm2_getcap properties-variable}
> +...
> +TPM2_PT_HR_PERSISTENT: 0x1
> +TPM2_PT_HR_PERSISTENT_AVAIL: 0x40
> +...
> +# @kbd{tpm2_getcap handles-persistent}
> +- 0x81000000
> +@end group
> +@end example
> +
> +In case the user doesn't want to use the TPM2 key protector anymore, besides
> +removing the sealed key file, here is the command to remove the persistent
The sealed key can be remove once the user does not want to use the TPM2
key protector anymore. Here is the command to remove the persistent ...
> +SRK handle (@samp{0x81000000}.) with @kbd{--tpm2-srk} and @kbd{--tpm2-evict}.
> +
> +@example
> +@group
> +# @kbd{grub-protect --action=remove \
> + --protector=tpm2 \
> + --tpm2-srk 0x81000000 \
> + --tpm2-evict}
> +@end group
> +@end example
> +
> +
> @node Invoking grub-script-check
> @section Invoking grub-script-check
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (32 preceding siblings ...)
2024-09-06 9:11 ` [PATCH v19 33/33] docs: Document TPM2 key protector Gary Lin via Grub-devel
@ 2024-09-13 14:32 ` Stefan Berger
2024-09-16 2:24 ` Gary Lin via Grub-devel
2024-10-03 15:58 ` Daniel Kiper
34 siblings, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-13 14:32 UTC (permalink / raw)
To: Gary Lin, The development of GNU GRUB
Cc: Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On 9/6/24 5:10 AM, Gary Lin wrote:
> GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
>
> This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> Hernan Gatta to introduce the key protector framework and TPM2 stack
> to GRUB2, and this could be a useful feature for the systems to
> implement full disk encryption.
>
> To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> Daniel Axtens's "appended signature secure boot support" (*3) to import
> libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> 4.19.0 instead of 4.16.0 in the original patch.
I was going to try it out now (on a ppc64 machine) but fail to configure
it. The configure and build work on tip of master.
> git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
[...]
Using python3...
Importing unicode...
Importing libgcrypt...
Importing libtasn1...
cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
directory
running: AUTOPOINT=true LIBTOOLIZE=true autoreconf --verbose --install
--force -I m4 --no-recursive
autoreconf: Entering directory `.'
autoreconf: running: true --force
autoreconf: running: aclocal -I m4 --force -I m4
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --include=m4 --force
autoreconf: running: /usr/bin/autoheader --include=m4 --force
autoreconf: running: automake --add-missing --copy --force-missing
configure.ac:50: installing 'build-aux/config.guess'
configure.ac:50: installing 'build-aux/config.sub'
configure.ac:56: installing 'build-aux/install-sh'
configure.ac:56: installing 'build-aux/missing'
automake: error: cannot open < Makefile.util.am: No such file or directory
autoreconf: automake failed with exit status: 1
./bootstrap: autoreconf failed
Bisecting the series of patches with the above command line run at each
step leads to:
70fff1f0d04f576921619fddaf066d1f2c73255c is the first bad commit
commit 70fff1f0d04f576921619fddaf066d1f2c73255c
Author: Daniel Axtens <dja@axtens.net>
Date: Fri Sep 6 17:11:07 2024 +0800
libtasn1: compile into asn1 module
Create a wrapper file that specifies the module license.
Set up the makefile so it is built.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
autogen.sh | 19 +++++++++++++++++++
grub-core/Makefile.core.def | 15 +++++++++++++++
grub-core/lib/libtasn1_wrap/wrap.c | 27 +++++++++++++++++++++++++++
3 files changed, 61 insertions(+)
create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-13 14:32 ` [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Stefan Berger
@ 2024-09-16 2:24 ` Gary Lin via Grub-devel
2024-09-16 3:35 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-16 2:24 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Fri, Sep 13, 2024 at 10:32:39AM -0400, Stefan Berger wrote:
>
>
> On 9/6/24 5:10 AM, Gary Lin wrote:
> > GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
> >
> > This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> > Hernan Gatta to introduce the key protector framework and TPM2 stack
> > to GRUB2, and this could be a useful feature for the systems to
> > implement full disk encryption.
> >
> > To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> > Daniel Axtens's "appended signature secure boot support" (*3) to import
> > libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> > 4.19.0 instead of 4.16.0 in the original patch.
>
>
> I was going to try it out now (on a ppc64 machine) but fail to configure it.
> The configure and build work on tip of master.
>
> > git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
> [...]
> Using python3...
> Importing unicode...
> Importing libgcrypt...
> Importing libtasn1...
> cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
> directory
That's weird. The second patch, "libtasn1: import libtasn1-4.19.0",
imports the libtasn1 files into grub-core/lib/libtasn1/, and those
source files are supposed to exist when applying the patch mentioned
below.
I'll do a thorough check for that...
Gary Lin
> running: AUTOPOINT=true LIBTOOLIZE=true autoreconf --verbose --install
> --force -I m4 --no-recursive
> autoreconf: Entering directory `.'
> autoreconf: running: true --force
> autoreconf: running: aclocal -I m4 --force -I m4
> autoreconf: configure.ac: tracing
> autoreconf: configure.ac: not using Libtool
> autoreconf: running: /usr/bin/autoconf --include=m4 --force
> autoreconf: running: /usr/bin/autoheader --include=m4 --force
> autoreconf: running: automake --add-missing --copy --force-missing
> configure.ac:50: installing 'build-aux/config.guess'
> configure.ac:50: installing 'build-aux/config.sub'
> configure.ac:56: installing 'build-aux/install-sh'
> configure.ac:56: installing 'build-aux/missing'
> automake: error: cannot open < Makefile.util.am: No such file or directory
> autoreconf: automake failed with exit status: 1
> ./bootstrap: autoreconf failed
>
>
>
> Bisecting the series of patches with the above command line run at each step
> leads to:
>
> 70fff1f0d04f576921619fddaf066d1f2c73255c is the first bad commit
> commit 70fff1f0d04f576921619fddaf066d1f2c73255c
> Author: Daniel Axtens <dja@axtens.net>
> Date: Fri Sep 6 17:11:07 2024 +0800
>
> libtasn1: compile into asn1 module
>
> Create a wrapper file that specifies the module license.
> Set up the makefile so it is built.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
>
> autogen.sh | 19 +++++++++++++++++++
> grub-core/Makefile.core.def | 15 +++++++++++++++
> grub-core/lib/libtasn1_wrap/wrap.c | 27 +++++++++++++++++++++++++++
> 3 files changed, 61 insertions(+)
> create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-16 2:24 ` Gary Lin via Grub-devel
@ 2024-09-16 3:35 ` Gary Lin via Grub-devel
2024-09-16 17:42 ` Stefan Berger
0 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-16 3:35 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Mon, Sep 16, 2024 at 10:24:03AM +0800, Gary Lin wrote:
> On Fri, Sep 13, 2024 at 10:32:39AM -0400, Stefan Berger wrote:
> >
> >
> > On 9/6/24 5:10 AM, Gary Lin wrote:
> > > GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
> > >
> > > This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> > > Hernan Gatta to introduce the key protector framework and TPM2 stack
> > > to GRUB2, and this could be a useful feature for the systems to
> > > implement full disk encryption.
> > >
> > > To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> > > Daniel Axtens's "appended signature secure boot support" (*3) to import
> > > libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> > > 4.19.0 instead of 4.16.0 in the original patch.
> >
> >
> > I was going to try it out now (on a ppc64 machine) but fail to configure it.
> > The configure and build work on tip of master.
> >
> > > git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
> > [...]
> > Using python3...
> > Importing unicode...
> > Importing libgcrypt...
> > Importing libtasn1...
> > cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
> > directory
> That's weird. The second patch, "libtasn1: import libtasn1-4.19.0",
> imports the libtasn1 files into grub-core/lib/libtasn1/, and those
> source files are supposed to exist when applying the patch mentioned
> below.
>
> I'll do a thorough check for that...
>
I successfully built the patches on a freshly-cloned grub git repo.
Since you mentioned ppc64, I wonder if it's caused by the conflicts with
the PowerPC Secure Boot patches?
Gary Lin
> Gary Lin
>
> > running: AUTOPOINT=true LIBTOOLIZE=true autoreconf --verbose --install
> > --force -I m4 --no-recursive
> > autoreconf: Entering directory `.'
> > autoreconf: running: true --force
> > autoreconf: running: aclocal -I m4 --force -I m4
> > autoreconf: configure.ac: tracing
> > autoreconf: configure.ac: not using Libtool
> > autoreconf: running: /usr/bin/autoconf --include=m4 --force
> > autoreconf: running: /usr/bin/autoheader --include=m4 --force
> > autoreconf: running: automake --add-missing --copy --force-missing
> > configure.ac:50: installing 'build-aux/config.guess'
> > configure.ac:50: installing 'build-aux/config.sub'
> > configure.ac:56: installing 'build-aux/install-sh'
> > configure.ac:56: installing 'build-aux/missing'
> > automake: error: cannot open < Makefile.util.am: No such file or directory
> > autoreconf: automake failed with exit status: 1
> > ./bootstrap: autoreconf failed
> >
> >
> >
> > Bisecting the series of patches with the above command line run at each step
> > leads to:
> >
> > 70fff1f0d04f576921619fddaf066d1f2c73255c is the first bad commit
> > commit 70fff1f0d04f576921619fddaf066d1f2c73255c
> > Author: Daniel Axtens <dja@axtens.net>
> > Date: Fri Sep 6 17:11:07 2024 +0800
> >
> > libtasn1: compile into asn1 module
> >
> > Create a wrapper file that specifies the module license.
> > Set up the makefile so it is built.
> >
> > Signed-off-by: Daniel Axtens <dja@axtens.net>
> > Signed-off-by: Gary Lin <glin@suse.com>
> > Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
> >
> > autogen.sh | 19 +++++++++++++++++++
> > grub-core/Makefile.core.def | 15 +++++++++++++++
> > grub-core/lib/libtasn1_wrap/wrap.c | 27 +++++++++++++++++++++++++++
> > 3 files changed, 61 insertions(+)
> > create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
> >
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-16 3:35 ` Gary Lin via Grub-devel
@ 2024-09-16 17:42 ` Stefan Berger
2024-09-17 19:23 ` Stefan Berger
` (2 more replies)
0 siblings, 3 replies; 82+ messages in thread
From: Stefan Berger @ 2024-09-16 17:42 UTC (permalink / raw)
To: Gary Lin
Cc: The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On 9/15/24 11:35 PM, Gary Lin wrote:
> On Mon, Sep 16, 2024 at 10:24:03AM +0800, Gary Lin wrote:
>> On Fri, Sep 13, 2024 at 10:32:39AM -0400, Stefan Berger wrote:
>>>
>>>
>>> On 9/6/24 5:10 AM, Gary Lin wrote:
>>>> GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
>>>>
>>>> This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
>>>> Hernan Gatta to introduce the key protector framework and TPM2 stack
>>>> to GRUB2, and this could be a useful feature for the systems to
>>>> implement full disk encryption.
>>>>
>>>> To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
>>>> Daniel Axtens's "appended signature secure boot support" (*3) to import
>>>> libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
>>>> 4.19.0 instead of 4.16.0 in the original patch.
>>>
>>>
>>> I was going to try it out now (on a ppc64 machine) but fail to configure it.
>>> The configure and build work on tip of master.
>>>
>>>> git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
>>> [...]
>>> Using python3...
>>> Importing unicode...
>>> Importing libgcrypt...
>>> Importing libtasn1...
>>> cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
>>> directory
>> That's weird. The second patch, "libtasn1: import libtasn1-4.19.0",
>> imports the libtasn1 files into grub-core/lib/libtasn1/, and those
>> source files are supposed to exist when applying the patch mentioned
>> below.
>>
>> I'll do a thorough check for that...
>>
> I successfully built the patches on a freshly-cloned grub git repo.
> Since you mentioned ppc64, I wonder if it's caused by the conflicts with
> the PowerPC Secure Boot patches?
I took your series from the mailing list with the b4 tool. For some
reason 02/33 is missing there, maybe because it is too big.
https://lore.kernel.org/grub-devel/20240916033543.gzfture5q4ljuw4b@GaryLaptop/T/#t
I checked out your repo branch and there I can configure but then run
into this issue here:
tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative
value [-Werror=shift-negative-value]
48 | unsigned long num = ((long) GRUB_UINT_MAX) << 2;
| ^~
cc1: all warnings being treated as errors
It's the cast to 'long' that this gcc complains about. If I remove the
cast then it works.
$ gcc --version
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-16 17:42 ` Stefan Berger
@ 2024-09-17 19:23 ` Stefan Berger
2024-09-18 3:12 ` Gary Lin via Grub-devel
2024-09-18 3:05 ` Gary Lin via Grub-devel
2024-09-19 7:59 ` Gary Lin via Grub-devel
2 siblings, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-17 19:23 UTC (permalink / raw)
To: Gary Lin
Cc: The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On 9/16/24 1:42 PM, Stefan Berger wrote:
>
>
> On 9/15/24 11:35 PM, Gary Lin wrote:
>> On Mon, Sep 16, 2024 at 10:24:03AM +0800, Gary Lin wrote:
>>> On Fri, Sep 13, 2024 at 10:32:39AM -0400, Stefan Berger wrote:
>>>>
>>>>
>>>> On 9/6/24 5:10 AM, Gary Lin wrote:
>>>>> GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
>>>>>
>>>>> This patch series is based on "Automatic TPM Disk Unlock"(*1)
>>>>> posted by
>>>>> Hernan Gatta to introduce the key protector framework and TPM2 stack
>>>>> to GRUB2, and this could be a useful feature for the systems to
>>>>> implement full disk encryption.
>>>>>
>>>>> To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed
>>>>> from
>>>>> Daniel Axtens's "appended signature secure boot support" (*3) to
>>>>> import
>>>>> libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
>>>>> 4.19.0 instead of 4.16.0 in the original patch.
>>>>
>>>>
>>>> I was going to try it out now (on a ppc64 machine) but fail to
>>>> configure it.
>>>> The configure and build work on tip of master.
>>>>
>>>>> git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
>>>> [...]
>>>> Using python3...
>>>> Importing unicode...
>>>> Importing libgcrypt...
>>>> Importing libtasn1...
>>>> cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
>>>> directory
>>> That's weird. The second patch, "libtasn1: import libtasn1-4.19.0",
>>> imports the libtasn1 files into grub-core/lib/libtasn1/, and those
>>> source files are supposed to exist when applying the patch mentioned
>>> below.
>>>
>>> I'll do a thorough check for that...
>>>
>> I successfully built the patches on a freshly-cloned grub git repo.
>> Since you mentioned ppc64, I wonder if it's caused by the conflicts with
>> the PowerPC Secure Boot patches?
>
> I took your series from the mailing list with the b4 tool. For some
> reason 02/33 is missing there, maybe because it is too big.
>
> https://lore.kernel.org/grub-devel/20240916033543.gzfture5q4ljuw4b@GaryLaptop/T/#t
>
> I checked out your repo branch and there I can configure but then run
> into this issue here:
>
> tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
> tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative
> value [-Werror=shift-negative-value]
> 48 | unsigned long num = ((long) GRUB_UINT_MAX) << 2;
> | ^~
> cc1: all warnings being treated as errors
>
> It's the cast to 'long' that this gcc complains about. If I remove the
> cast then it works.
>
> $ gcc --version
> gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
> Copyright (C) 2019 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
I got this error when libtasn1 was not installed on the host. Do you
still need libtasn1 installed now that its part of the repo with your
series?
checking for libnvpair.h... no
checking for libzfs_init in -lzfs... no
checking for asn1_write_value in -ltasn1... no
configure: error: grub-protect was explicitly requested but can't be
compiled (need libtasn1 library)
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-16 17:42 ` Stefan Berger
2024-09-17 19:23 ` Stefan Berger
@ 2024-09-18 3:05 ` Gary Lin via Grub-devel
2024-09-18 14:09 ` Stefan Berger
2024-09-19 7:59 ` Gary Lin via Grub-devel
2 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-18 3:05 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Mon, Sep 16, 2024 at 01:42:18PM -0400, Stefan Berger wrote:
>
>
> On 9/15/24 11:35 PM, Gary Lin wrote:
> > On Mon, Sep 16, 2024 at 10:24:03AM +0800, Gary Lin wrote:
> > > On Fri, Sep 13, 2024 at 10:32:39AM -0400, Stefan Berger wrote:
> > > >
> > > >
> > > > On 9/6/24 5:10 AM, Gary Lin wrote:
> > > > > GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
> > > > >
> > > > > This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> > > > > Hernan Gatta to introduce the key protector framework and TPM2 stack
> > > > > to GRUB2, and this could be a useful feature for the systems to
> > > > > implement full disk encryption.
> > > > >
> > > > > To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> > > > > Daniel Axtens's "appended signature secure boot support" (*3) to import
> > > > > libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> > > > > 4.19.0 instead of 4.16.0 in the original patch.
> > > >
> > > >
> > > > I was going to try it out now (on a ppc64 machine) but fail to configure it.
> > > > The configure and build work on tip of master.
> > > >
> > > > > git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
> > > > [...]
> > > > Using python3...
> > > > Importing unicode...
> > > > Importing libgcrypt...
> > > > Importing libtasn1...
> > > > cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
> > > > directory
> > > That's weird. The second patch, "libtasn1: import libtasn1-4.19.0",
> > > imports the libtasn1 files into grub-core/lib/libtasn1/, and those
> > > source files are supposed to exist when applying the patch mentioned
> > > below.
> > >
> > > I'll do a thorough check for that...
> > >
> > I successfully built the patches on a freshly-cloned grub git repo.
> > Since you mentioned ppc64, I wonder if it's caused by the conflicts with
> > the PowerPC Secure Boot patches?
>
> I took your series from the mailing list with the b4 tool. For some reason
> 02/33 is missing there, maybe because it is too big.
>
> https://lore.kernel.org/grub-devel/20240916033543.gzfture5q4ljuw4b@GaryLaptop/T/#t
>
> I checked out your repo branch and there I can configure but then run into
> this issue here:
>
> tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
> tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative value
> [-Werror=shift-negative-value]
> 48 | unsigned long num = ((long) GRUB_UINT_MAX) << 2;
> | ^~
> cc1: all warnings being treated as errors
>
> It's the cast to 'long' that this gcc complains about. If I remove the cast
> then it works.
>
Urgh, the cast looks wrong. I'll remove the cast.
Gary Lin
> $ gcc --version
> gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
> Copyright (C) 2019 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-17 19:23 ` Stefan Berger
@ 2024-09-18 3:12 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-18 3:12 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On Tue, Sep 17, 2024 at 03:23:00PM -0400, Stefan Berger wrote:
>
>
> On 9/16/24 1:42 PM, Stefan Berger wrote:
> >
> >
> > On 9/15/24 11:35 PM, Gary Lin wrote:
> > > On Mon, Sep 16, 2024 at 10:24:03AM +0800, Gary Lin wrote:
> > > > On Fri, Sep 13, 2024 at 10:32:39AM -0400, Stefan Berger wrote:
> > > > >
> > > > >
> > > > > On 9/6/24 5:10 AM, Gary Lin wrote:
> > > > > > GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
> > > > > >
> > > > > > This patch series is based on "Automatic TPM Disk
> > > > > > Unlock"(*1) posted by
> > > > > > Hernan Gatta to introduce the key protector framework and TPM2 stack
> > > > > > to GRUB2, and this could be a useful feature for the systems to
> > > > > > implement full disk encryption.
> > > > > >
> > > > > > To support TPM 2.0 Key File format(*2), patch 1~7,9-16
> > > > > > are grabbed from
> > > > > > Daniel Axtens's "appended signature secure boot support"
> > > > > > (*3) to import
> > > > > > libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> > > > > > 4.19.0 instead of 4.16.0 in the original patch.
> > > > >
> > > > >
> > > > > I was going to try it out now (on a ppc64 machine) but fail
> > > > > to configure it.
> > > > > The configure and build work on tip of master.
> > > > >
> > > > > > git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
> > > > > [...]
> > > > > Using python3...
> > > > > Importing unicode...
> > > > > Importing libgcrypt...
> > > > > Importing libtasn1...
> > > > > cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
> > > > > directory
> > > > That's weird. The second patch, "libtasn1: import libtasn1-4.19.0",
> > > > imports the libtasn1 files into grub-core/lib/libtasn1/, and those
> > > > source files are supposed to exist when applying the patch mentioned
> > > > below.
> > > >
> > > > I'll do a thorough check for that...
> > > >
> > > I successfully built the patches on a freshly-cloned grub git repo.
> > > Since you mentioned ppc64, I wonder if it's caused by the conflicts with
> > > the PowerPC Secure Boot patches?
> >
> > I took your series from the mailing list with the b4 tool. For some
> > reason 02/33 is missing there, maybe because it is too big.
> >
> > https://lore.kernel.org/grub-devel/20240916033543.gzfture5q4ljuw4b@GaryLaptop/T/#t
> >
> > I checked out your repo branch and there I can configure but then run
> > into this issue here:
> >
> > tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
> > tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative
> > value [-Werror=shift-negative-value]
> > 48 | unsigned long num = ((long) GRUB_UINT_MAX) << 2;
> > | ^~
> > cc1: all warnings being treated as errors
> >
> > It's the cast to 'long' that this gcc complains about. If I remove the
> > cast then it works.
> >
> > $ gcc --version
> > gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
> > Copyright (C) 2019 Free Software Foundation, Inc.
> > This is free software; see the source for copying conditions. There is NO
> > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
> I got this error when libtasn1 was not installed on the host. Do you still
> need libtasn1 installed now that its part of the repo with your series?
>
> checking for libnvpair.h... no
> checking for libzfs_init in -lzfs... no
> checking for asn1_write_value in -ltasn1... no
> configure: error: grub-protect was explicitly requested but can't be
> compiled (need libtasn1 library)
There are several disabled functions in the built-in libtasn1, and one
of them is asn1_write_value(). Grub-protect needs the function to create
the asn1 object, but GRUB itself only needs the parsing functions, so in
the end I make grub-protect to use the external libtasn1.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support
2024-09-06 9:11 ` [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support Gary Lin via Grub-devel
@ 2024-09-18 3:14 ` Stefan Berger
2024-09-18 7:28 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-18 3:14 UTC (permalink / raw)
To: Gary Lin, The development of GNU GRUB
Cc: Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On 9/6/24 5:11 AM, Gary Lin wrote:
> A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to
> compose and submit TPM commands and parse reponses.
>
> +static TPM_RC_t
> +tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG_t tag,
> + const TPM_CC_t commandCode,
> + TPM_RC_t *responseCode,
> + const struct grub_tpm2_buffer *in,
> + struct grub_tpm2_buffer *out)
> +{
> + grub_err_t err;
> + struct grub_tpm2_buffer buf;
> + TPMI_ST_COMMAND_TAG_t tag_out;
> + grub_uint32_t command_size;
> + grub_size_t max_output_size;
> +
> + /* Marshal */
> + grub_tpm2_buffer_init (&buf);
> + grub_tpm2_buffer_pack_u16 (&buf, tag);
> + grub_tpm2_buffer_pack_u32 (&buf, 0);
> + grub_tpm2_buffer_pack_u32 (&buf, commandCode);
> + grub_tpm2_buffer_pack (&buf, in->data, in->size);
> +
> + if (buf.error != 0)
> + return TPM_RC_FAILURE;
> +
> + command_size = grub_swap_bytes32 (buf.size);
> + grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size,
> + sizeof (command_size));
This is odd. So UEFI requires that the command size is in little endian
while the TPM commands are typically all in big endian format? If so,
could you push this into the grub_tcg2_submit_command? Other firmware
doesn't need this odd endianess switch and could just leave the size
as-is and just pass the TPM command to the device without switching
endianess again.
I am working on changes for ppc64 to also support this. So, indeed,
there are some parts that are EFI-specific at the moment.
Stefan
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support
2024-09-18 3:14 ` Stefan Berger
@ 2024-09-18 7:28 ` Gary Lin via Grub-devel
2024-10-01 14:48 ` Daniel Kiper
0 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-18 7:28 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On Tue, Sep 17, 2024 at 11:14:33PM -0400, Stefan Berger wrote:
>
>
> On 9/6/24 5:11 AM, Gary Lin wrote:
> > A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to
> > compose and submit TPM commands and parse reponses.
> >
>
> > +static TPM_RC_t
> > +tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG_t tag,
> > + const TPM_CC_t commandCode,
> > + TPM_RC_t *responseCode,
> > + const struct grub_tpm2_buffer *in,
> > + struct grub_tpm2_buffer *out)
> > +{
> > + grub_err_t err;
> > + struct grub_tpm2_buffer buf;
> > + TPMI_ST_COMMAND_TAG_t tag_out;
> > + grub_uint32_t command_size;
> > + grub_size_t max_output_size;
> > +
> > + /* Marshal */
> > + grub_tpm2_buffer_init (&buf);
> > + grub_tpm2_buffer_pack_u16 (&buf, tag);
> > + grub_tpm2_buffer_pack_u32 (&buf, 0);
> > + grub_tpm2_buffer_pack_u32 (&buf, commandCode);
> > + grub_tpm2_buffer_pack (&buf, in->data, in->size);
> > +
> > + if (buf.error != 0)
> > + return TPM_RC_FAILURE;
> > +
> > + command_size = grub_swap_bytes32 (buf.size);
> > + grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size,
> > + sizeof (command_size));
>
> This is odd. So UEFI requires that the command size is in little endian
> while the TPM commands are typically all in big endian format? If so, could
> you push this into the grub_tcg2_submit_command? Other firmware doesn't need
> this odd endianess switch and could just leave the size as-is and just pass
> the TPM command to the device without switching endianess again.
EFI_TCG2_PROTOCOL.SubmitCommand() expects the little-endian
InputParameterBlockSize, and InputParameterBlock in big-endian for the
TPM command stream.
Actually, the code is also needed when running grub-emu on a
little-endian system. Maybe we can add an additional check for the
endianness here and only run the code for the little-endian systems.
> I am working on changes for ppc64 to also support this. So, indeed, there
> are some parts that are EFI-specific at the moment.
Thanks for working on ppc64! That's something I'm not familiar with,
and, yes, there are likely several EFI-specific parts due to my
blind spots.
Gary Lin
>
> Stefan
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-18 3:05 ` Gary Lin via Grub-devel
@ 2024-09-18 14:09 ` Stefan Berger
2024-09-18 15:17 ` Stefan Berger
0 siblings, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-18 14:09 UTC (permalink / raw)
To: Gary Lin
Cc: The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On 9/17/24 11:05 PM, Gary Lin wrote:
> On Mon, Sep 16, 2024 at 01:42:18PM -0400, Stefan Berger wrote:
>> tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
>> tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative value
>> [-Werror=shift-negative-value]
>> 48 | unsigned long num = ((long) GRUB_UINT_MAX) << 2;
>> | ^~
>> cc1: all warnings being treated as errors
>>
>> It's the cast to 'long' that this gcc complains about. If I remove the cast
>> then it works.
>>
> Urgh, the cast looks wrong. I'll remove the cast.
While I am trying things out...
grub-protect should display an error message when it cannot find
--tpm2-keyfile. It exits with status code 5 but an error message is missing.
I also seem to have an issue with --tpm2key parameter passed to
grub-protect per the documentation but then grub using
'tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tp'
complains about the TPM wire format not being correct. I had to omit
this parameter from grub-protect for the key to be unmarshall'able. I
also haven't looked whether there's a parameter to
tpm2_key_protectore_init to hint at the different key format. Ideally it
would figure this out by itself or there was only one format...
ppc64 runs grub in big endian mode, so there may be some issues due to
that -- with bitfields for sure: Currently trying to figure out how it
is unmarshalling the PCR selection (not a bitfield). When sealing to pcr
0 it marshalled 0x01 0x00 0x00, which is correct but when unmarshalling
it is unmarshalls 0x80 0x00 0x00 - odd.
>
> Gary Lin
>
>> $ gcc --version
>> gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
>> Copyright (C) 2019 Free Software Foundation, Inc.
>> This is free software; see the source for copying conditions. There is NO
>> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-18 14:09 ` Stefan Berger
@ 2024-09-18 15:17 ` Stefan Berger
0 siblings, 0 replies; 82+ messages in thread
From: Stefan Berger @ 2024-09-18 15:17 UTC (permalink / raw)
To: Gary Lin
Cc: The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On 9/18/24 10:09 AM, Stefan Berger wrote:
>
>
> On 9/17/24 11:05 PM, Gary Lin wrote:
>> On Mon, Sep 16, 2024 at 01:42:18PM -0400, Stefan Berger wrote:
>
>>> tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
>>> tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative
>>> value
>>> [-Werror=shift-negative-value]
>>> 48 | unsigned long num = ((long) GRUB_UINT_MAX) << 2;
>>> | ^~
>>> cc1: all warnings being treated as errors
>>>
>>> It's the cast to 'long' that this gcc complains about. If I remove
>>> the cast
>>> then it works.
>>>
>> Urgh, the cast looks wrong. I'll remove the cast.
>
> While I am trying things out...
>
> grub-protect should display an error message when it cannot find
> --tpm2-keyfile. It exits with status code 5 but an error message is
> missing.
>
> I also seem to have an issue with --tpm2key parameter passed to
> grub-protect per the documentation but then grub using
> 'tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tp'
> complains about the TPM wire format not being correct. I had to omit
> this parameter from grub-protect for the key to be unmarshall'able. I
> also haven't looked whether there's a parameter to
> tpm2_key_protectore_init to hint at the different key format. Ideally it
> would figure this out by itself or there was only one format...
>
> ppc64 runs grub in big endian mode, so there may be some issues due to
> that -- with bitfields for sure: Currently trying to figure out how it
> is unmarshalling the PCR selection (not a bitfield). When sealing to pcr
> 0 it marshalled 0x01 0x00 0x00, which is correct but when unmarshalling
> it is unmarshalls 0x80 0x00 0x00 - odd.
This 0x80 stems from the default value for selected PCRs (PCR 7) when
none is selected. I had taken the line from the documentation and not
added --pcrs 0 reflecting the same pcr selection I had chosen when using
grub-protect and that's why it didn't work. So all is good.
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 22/33] key_protector: Add TPM2 Key Protector
2024-09-06 9:11 ` [PATCH v19 22/33] key_protector: Add TPM2 Key Protector Gary Lin via Grub-devel
@ 2024-09-18 15:22 ` Stefan Berger
2024-09-19 7:45 ` Gary Lin via Grub-devel
2024-10-16 15:44 ` Daniel Kiper
1 sibling, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-18 15:22 UTC (permalink / raw)
To: The development of GNU GRUB
Cc: Gary Lin, Daniel Kiper, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On 9/6/24 5:11 AM, Gary Lin via Grub-devel wrote:
> From: Hernan Gatta <hegatta@linux.microsoft.com>
>
> The TPM2 key protector is a module that enables the automatic retrieval
> of a fully-encrypted disk's unlocking key from a TPM 2.0.
>
> The theory of operation is such that the module accepts various
> arguments, most of which are optional and therefore possess reasonable
> defaults. One of these arguments is the keyfile/tpm2key parameter, which
> is mandatory. There are two supported key formats:
>
> +}
> +
> +grub_err_t
> +grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle)
> +{
> + grub_uint64_t num;
> + const char *str_end;
> +
> + grub_errno = GRUB_ERR_NONE;
> + num = grub_strtoul (value, &str_end, 0);
> + if (*value == '\0' || *str_end != '\0')
> + return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is not a number", value);
> +
> + if (num > GRUB_UINT_MAX)
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
commands/tpm2_key_protector/args.c: In function
‘grub_tpm2_protector_parse_tpm_handle’:
commands/tpm2_key_protector/args.c:124:56: error: format ‘%lu’ expects
argument of type ‘long unsigned int’, but argument 3 has type
‘grub_uint64_t’ {aka ‘long long unsigned int’} [-Werror=format=]
124 | return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too
large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
| ~~^
~~~
| |
|
| long
unsigned int
grub_uint64_t {aka long long unsigned int}
| %llu
cc1: all warnings being treated as errors
Changing this to %llu leads to:
grub-core/commands/tpm2_key_protector/args.c: In function
‘grub_tpm2_protector_parse_tpm_handle’:
grub-core/commands/tpm2_key_protector/args.c:124:57: error: format
‘%llu’ expects argument of type ‘long long unsigned int’, but argument 3
has type ‘grub_uint64_t’ {aka ‘long unsigned int’} [-Werror=format=]
124 | return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %llu is
too large to be a TPM handle, TPM handles are unsigned 32-bit integers",
num);
| ~~~^
~~~
| |
|
| long
long unsigned int
grub_uint64_t {aka long unsigned int}
| %lu
cc1: all warnings being treated as errors
Can't win . This works:
diff --git a/grub-core/commands/tpm2_key_protector/args.c
b/grub-core/commands/tpm2_key_protector/args.c
index c58cbe307..749db81a5 100644
--- a/grub-core/commands/tpm2_key_protector/args.c
+++ b/grub-core/commands/tpm2_key_protector/args.c
@@ -121,7 +121,7 @@ grub_tpm2_protector_parse_tpm_handle (const char
*value, TPM_HANDLE_t *handle)
return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is
not a number", value);
if (num > GRUB_UINT_MAX)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large
to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large
to be a TPM handle, TPM handles are unsigned 32-bit integers", (unsigned
long)num);
*handle = (TPM_HANDLE_t) num;
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] 82+ messages in thread
* Re: [PATCH v19 22/33] key_protector: Add TPM2 Key Protector
2024-09-18 15:22 ` Stefan Berger
@ 2024-09-19 7:45 ` Gary Lin via Grub-devel
2024-09-19 15:05 ` Stefan Berger
0 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-19 7:45 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Wed, Sep 18, 2024 at 11:22:16AM -0400, Stefan Berger wrote:
>
>
> On 9/6/24 5:11 AM, Gary Lin via Grub-devel wrote:
> > From: Hernan Gatta <hegatta@linux.microsoft.com>
> >
> > The TPM2 key protector is a module that enables the automatic retrieval
> > of a fully-encrypted disk's unlocking key from a TPM 2.0.
> >
> > The theory of operation is such that the module accepts various
> > arguments, most of which are optional and therefore possess reasonable
> > defaults. One of these arguments is the keyfile/tpm2key parameter, which
> > is mandatory. There are two supported key formats:
> >
>
> > +}
> > +
> > +grub_err_t
> > +grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle)
> > +{
> > + grub_uint64_t num;
> > + const char *str_end;
> > +
> > + grub_errno = GRUB_ERR_NONE;
> > + num = grub_strtoul (value, &str_end, 0);
> > + if (*value == '\0' || *str_end != '\0')
> > + return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is not a number", value);
> > +
> > + if (num > GRUB_UINT_MAX)
> > + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
>
> commands/tpm2_key_protector/args.c: In function
> ‘grub_tpm2_protector_parse_tpm_handle’:
> commands/tpm2_key_protector/args.c:124:56: error: format ‘%lu’ expects
> argument of type ‘long unsigned int’, but argument 3 has type
> ‘grub_uint64_t’ {aka ‘long long unsigned int’} [-Werror=format=]
> 124 | return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too
> large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
> | ~~^
> ~~~
> | |
> |
> | long unsigned
> int grub_uint64_t {aka long long unsigned int}
> | %llu
> cc1: all warnings being treated as errors
>
>
> Changing this to %llu leads to:
>
> grub-core/commands/tpm2_key_protector/args.c: In function
> ‘grub_tpm2_protector_parse_tpm_handle’:
> grub-core/commands/tpm2_key_protector/args.c:124:57: error: format ‘%llu’
> expects argument of type ‘long long unsigned int’, but argument 3 has type
> ‘grub_uint64_t’ {aka ‘long unsigned int’} [-Werror=format=]
> 124 | return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %llu is too
> large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
> | ~~~^
> ~~~
> | |
> |
> | long long
> unsigned int grub_uint64_t {aka long unsigned int}
> | %lu
> cc1: all warnings being treated as errors
>
>
> Can't win . This works:
>
> diff --git a/grub-core/commands/tpm2_key_protector/args.c
> b/grub-core/commands/tpm2_key_protector/args.c
> index c58cbe307..749db81a5 100644
> --- a/grub-core/commands/tpm2_key_protector/args.c
> +++ b/grub-core/commands/tpm2_key_protector/args.c
> @@ -121,7 +121,7 @@ grub_tpm2_protector_parse_tpm_handle (const char *value,
> TPM_HANDLE_t *handle)
> return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is not a
> number", value);
>
> if (num > GRUB_UINT_MAX)
> - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be
> a TPM handle, TPM handles are unsigned 32-bit integers", num);
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be
> a TPM handle, TPM handles are unsigned 32-bit integers", (unsigned
> long)num);
>
> *handle = (TPM_HANDLE_t) num;
>
How about this change?
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value " PRIuGRUB_UINT64_T " is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
Here we use the type macro to choose the correct type string for
'grub_uint64_t' to avoid the potential compiler error.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-16 17:42 ` Stefan Berger
2024-09-17 19:23 ` Stefan Berger
2024-09-18 3:05 ` Gary Lin via Grub-devel
@ 2024-09-19 7:59 ` Gary Lin via Grub-devel
2 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-19 7:59 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Mon, Sep 16, 2024 at 01:42:18PM -0400, Stefan Berger wrote:
>
>
> On 9/15/24 11:35 PM, Gary Lin wrote:
> > On Mon, Sep 16, 2024 at 10:24:03AM +0800, Gary Lin wrote:
> > > On Fri, Sep 13, 2024 at 10:32:39AM -0400, Stefan Berger wrote:
> > > >
> > > >
> > > > On 9/6/24 5:10 AM, Gary Lin wrote:
> > > > > GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
> > > > >
> > > > > This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> > > > > Hernan Gatta to introduce the key protector framework and TPM2 stack
> > > > > to GRUB2, and this could be a useful feature for the systems to
> > > > > implement full disk encryption.
> > > > >
> > > > > To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> > > > > Daniel Axtens's "appended signature secure boot support" (*3) to import
> > > > > libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> > > > > 4.19.0 instead of 4.16.0 in the original patch.
> > > >
> > > >
> > > > I was going to try it out now (on a ppc64 machine) but fail to configure it.
> > > > The configure and build work on tip of master.
> > > >
> > > > > git clean -xdf ; ./bootstrap && ./configure --prefix=/usr
> > > > [...]
> > > > Using python3...
> > > > Importing unicode...
> > > > Importing libgcrypt...
> > > > Importing libtasn1...
> > > > cp: cannot stat 'grub-core/lib/libtasn1/lib/*.[ch]': No such file or
> > > > directory
> > > That's weird. The second patch, "libtasn1: import libtasn1-4.19.0",
> > > imports the libtasn1 files into grub-core/lib/libtasn1/, and those
> > > source files are supposed to exist when applying the patch mentioned
> > > below.
> > >
> > > I'll do a thorough check for that...
> > >
> > I successfully built the patches on a freshly-cloned grub git repo.
> > Since you mentioned ppc64, I wonder if it's caused by the conflicts with
> > the PowerPC Secure Boot patches?
>
> I took your series from the mailing list with the b4 tool. For some reason
> 02/33 is missing there, maybe because it is too big.
>
> https://lore.kernel.org/grub-devel/20240916033543.gzfture5q4ljuw4b@GaryLaptop/T/#t
>
> I checked out your repo branch and there I can configure but then run into
> this issue here:
>
> tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
> tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative value
> [-Werror=shift-negative-value]
> 48 | unsigned long num = ((long) GRUB_UINT_MAX) << 2;
> | ^~
> cc1: all warnings being treated as errors
>
> It's the cast to 'long' that this gcc complains about. If I remove the cast
> then it works.
>
Hmm the cast is actually inherited from the original test from
libtasn1, and my patch just replaces UINT_MAX with GRUB_UINT_MAX.
The original patch from Daniel Axtens replaces the if statement with
'#if':
- if (LONG_MAX > INT_MAX)
+#if (GRUB_LONG_MAX > GRUB_INT_MAX)
+ {
+- unsigned long num = ((long) UINT_MAX) << 2;
++ unsigned long num = ((long) GRUB_UINT_MAX) << 2;
...
+ }
++#endif
Maybe I should restore that part to avoid the cast error in some
architectures.
Gary Lin
> $ gcc --version
> gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0
> Copyright (C) 2019 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 22/33] key_protector: Add TPM2 Key Protector
2024-09-19 7:45 ` Gary Lin via Grub-devel
@ 2024-09-19 15:05 ` Stefan Berger
2024-09-20 2:17 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-19 15:05 UTC (permalink / raw)
To: Gary Lin
Cc: The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On 9/19/24 3:45 AM, Gary Lin wrote:
> On Wed, Sep 18, 2024 at 11:22:16AM -0400, Stefan Berger wrote:
>>
>>
>> *handle = (TPM_HANDLE_t) num;
>>
> How about this change?
>
> - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value " PRIuGRUB_UINT64_T " is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
>
There's a missing "%" but it works for me:
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %"
PRIuGRUB_UINT64_T " is too large to be a TPM handle, TPM handles are
unsigned 32-bit integers", num);
> Here we use the type macro to choose the correct type string for
> 'grub_uint64_t' to avoid the potential compiler error.
>
> Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 22/33] key_protector: Add TPM2 Key Protector
2024-09-19 15:05 ` Stefan Berger
@ 2024-09-20 2:17 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-20 2:17 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Thu, Sep 19, 2024 at 11:05:13AM -0400, Stefan Berger wrote:
>
>
> On 9/19/24 3:45 AM, Gary Lin wrote:
> > On Wed, Sep 18, 2024 at 11:22:16AM -0400, Stefan Berger wrote:
> > >
> > >
>
> > > *handle = (TPM_HANDLE_t) num;
> > >
> > How about this change?
> >
> > - return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
> > + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value " PRIuGRUB_UINT64_T " is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
> >
> There's a missing "%" but it works for me:
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %" PRIuGRUB_UINT64_T "
> is too large to be a TPM handle, TPM handles are unsigned 32-bit integers",
> num);
>
Thanks! I'll update the string to fix the type error.
Gary Lin
> > Here we use the type macro to choose the correct type string for
> > 'grub_uint64_t' to avoid the potential compiler error.
> >
> > Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 33/33] docs: Document TPM2 key protector
2024-09-13 14:25 ` Stefan Berger
@ 2024-09-20 8:16 ` Gary Lin via Grub-devel
2024-09-20 13:42 ` Stefan Berger
0 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-09-20 8:16 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Fri, Sep 13, 2024 at 10:25:14AM -0400, Stefan Berger wrote:
>
>
> On 9/6/24 5:11 AM, Gary Lin wrote:
> > Update the user manual to address TPM2 key protector including the two
> > related commands, tpm2_key_protector_init and tpm2_key_protector_clear,
> > and the user-space utility: grub-protect.
> >
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> > docs/grub.texi | 507 +++++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 507 insertions(+)
> >
> > diff --git a/docs/grub.texi b/docs/grub.texi
> > index 3e6f602b2..30548ac57 100644
> > --- a/docs/grub.texi
> > +++ b/docs/grub.texi
> > @@ -6443,6 +6443,8 @@ you forget a command, you can run the command @command{help}
> > * smbios:: Retrieve SMBIOS information
> > * source:: Read a configuration file in same context
> > * test:: Check file types and compare values
> > +* tpm2_key_protector_init:: Initialize the TPM2 key protector
> > +* tpm2_key_protector_clear:: Clear the TPM2 key protector
> > * true:: Do nothing, successfully
> > * trust:: Add public key to list of trusted keys
> > * unset:: Unset an environment variable
> > @@ -8000,6 +8002,56 @@ either @var{expression1} or @var{expression2} is true
> > @end table
> > @end deffn
> > +@node tpm2_key_protector_init
> > +@subsection tpm2_key_protector_init
> > +
> > +@deffn Command tpm2_key_protector_init [@option{-m} mode] | [@option{-p} pcrlist] | [@option{-b} pcrbank] | [ [@option{-T} tpm2key_file] | [@option{-k} keyfile] ] | [@option{-s} handle] | [@option{-a} srk_type] | [@option{-n} nv_index]
> > +Initialize the TPM2 key protector to unseal the key for the @command{cryptomount}
> > +(@pxref{cryptomount}) command. There are two supported mode,
>
> s/mode/modes
>
Will fix it in the next version.
> > +SRK(@kbd{srk}) and NV index(@kbd{nv}), to be specified by the option
> > +@option{-m}. The default mode is srk. The main difference between SRK mode
>
> s/srk/SRK
>
ditto
> > +and NV index mode is the storage of the sealed key. For SRK mode, the sealed
> > +key is stored in a file while NV index mode stores the sealed key in the
> > +non-volatile memory inside TPM with a given NV index.
> > +
> > +The @option{-p} and @option{-b} options are used to supply the PCR list and
> > +bank that the key sealed with. The PCR list is a comma-separated list, e.g.,
>
> key is sealed with (?)
>
ditto
> > +'0,2,4,7,9', to represent the involved PCRs, and the default is '7'. The PCR
> > +bank is marked by the hash algorithms. The current supported PCR banks are
>
> bank is chosen by selecting a hash algorithm (?)
>
ditto
> > +SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
> > +
> > +There are some options only available for the specific mode. The SRK-specific
> > +options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
> > +other hand, the NV index-specific option is @option{-n}.
> > +
> > +The key file for SRK mode can be supplied with either @option{-T} or
> > +@option{-k}. The @option{-T} option is for the path to the key file in
> > +the TPM 2.0 Key File format. Since the parameters for the TPM commands are
> > +written in the policy sequences, there is no need to set the PCR
>
> What is 'the policy sequences' ?
>
It's the TPMPolicy sequence which contains the command code and the
parameters.
https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-tpmpolicy-syntax
> > +list(@option{-p}) and bank(@option{-b}) when using @option{-T} option. The
>
> the @option{-T} option
>
Will fix it in the next version.
> > +@option{-k} option is for the key file in the raw format, and the @option{-p}
> > +and @option{-b} options are necessary for the non-default PCR list or bank.
> > +
> > +Besides the key file, there are two options, @option{-a} and @option{-s}, to
> > +tweak the TPM Storage Root Key (SRK). The SRK can be either created at
> > +runtime or stored in the non-volatile memory. When creating SRK at runtime,
> > +GRUB provides the SRK template to TPM to create the key. There are two SRK
> > +templates, ECC and RSA, for the @option{-a} option and the default is ECC.
> > +If the SRK is stored in a specific handle, e.g. @code{0x81000001}, the
> > +@option{-s} option can be used to set the handle to notify GRUB to load
> > +the SRK from the given handle.
> > +
> > +The only nvindex-specific option is the option @option{-n} which is used to
> > +set the NV index containing the sealed key, so that GRUB can load the sealed
> > +key and unseal it with the given PCR list and bank.
> > +@end deffn
> > +
> > +@node tpm2_key_protector_clear
> > +@subsection tpm2_key_protector_clear
> > +
> > +@deffn Command tpm2_key_protector_clear
> > +Clear the TPM2 key protector if previously initialized.
> > +@end deffn
> > @node true
> > @subsection true
> > @@ -8528,6 +8580,7 @@ environment variables and commands are listed in the same order.
> > * Secure Boot Advanced Targeting:: Embedded information for generation number based revocation
> > * Measured Boot:: Measuring boot components
> > * Lockdown:: Lockdown when booting on a secure setup
> > +* TPM2 key protector:: Managing disk key with TPM2 key protector
> > @end menu
> > @node Authentication and authorisation
> > @@ -8771,6 +8824,295 @@ be restricted and some operations/commands cannot be executed.
> > The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
> > Otherwise it does not exit.
> > +@node TPM2 key protector
> > +@section TPM2 key protector in GRUB
> > +
> > +TPM2 key protector extends measured boot to unlock the encrypted partition
> > +without user intervention. It uses the TPM Storage Root Key (SRK) to seal
> > +the disk key with a given set of PCR values. If the system state matches,
> > +i.e. PCR values match the sealed PCR set, TPM2 key protector unseals the
> > +disk key for @command{cryptomount} (@pxref{cryptomount}) to unlock the
> > +encrypted partition. (In case the unsealed key fails to unlock the
> > +partition, @command{cryptomount} falls back to the passphrase prompt.)
> > +
> > +There are two supported modes to store the sealed key, SRK and NV index,
> > +and the details will be addressed in the latter sections.
>
> s/in the latter sections/in later sections?
>
Will fix it in the next version.
> > +
> > +TPM2 key protector is currently only supported on EFI and EMU platforms.
>
> When I looked through the patches I did not see anything particularly
> related to EFI. Is it only available on EFI and EMU platforms because you
> did not test it with a (Sea)BIOS for example ? I was actually going to try
> it on PPC64 on KVM that has SLOF firmware.
>
It's related to the tcg2 functions defined in grub-core/lib/tss2/tcg2.h.
Currently, there is only two implementations:
EFI: grub-core/lib/efi/tcg2.c
EMU: grub-core/lib/tss2/tcg2_emu.c
> > +
> > +@subsection TPM PCR usage
> > +
> > +Since TPM2 key protector relies on PCRs to check the system state, it is
> > +important to decide which PCRs to seal the key with. The following table
> > +shows the users of PCRs and the measured objects on EFI platforms.
> > +
> > +@multitable @columnfractions 0.1 0.2 0.7
> > +@headitem PCR @tab Used by @tab Measured Objects
> > +@item 0
> > +@tab Firmware
> > +@tab Core system firmware executable code
> > +@item 1
> > +@tab Firmware
> > +@tab Core system firmware data/host platform configuration; typically
> > +contains serial and model numbers
> > +@item 2
> > +@tab Firmware
> > +@tab Extended or pluggable executable code; includes option ROMs on
> > +pluggable hardware
> > +@item 3
> > +@tab Firmware
> > +@tab Extended or pluggable firmware data; includes information about
> > +pluggable hardware
> > +@item 4
> > +@tab Firmware
> > +@tab Boot loader and additional drivers; binaries and extensions loaded
> > +by the boot loader
> > +@item 5
> > +@tab Firmware
> > +@tab GPT/Partition table
> > +@item 7
> > +@tab Firmware
> > +@tab SecureBoot state
> > +@item 8
> > +@tab GRUB
> > +@tab Commands and kernel command line
> > +@item 9
> > +@tab GRUB
> > +@tab All files read (including kernel image)
> > +@item 9
> > +@tab Linux Kernel
> > +@tab All passed initrds (when the new LOAD_FILE2 initrd protocol is used)
> > +@item 10
> > +@tab Linux Kernel
> > +@tab Protection of the IMA measurement log
> > +@item 14
> > +@tab shim
> > +@tab “MOK” certificates and hashes
> > +@end multitable
> > +
> > +PCR 0, 2, 4, and 7 can be used to check the integrity of the firmware code
> > +and bootloaders. PCR 8 and 9 are useful to check the file and data processed
> > +by GRUB. PCRs 10, 11, 12, 13, and 15 are controlled by the operating system,
> > +so those PCRs are usually still in the initial state when GRUB is running.
> > +
> > +In general, it is nice to include PCR 0, 2, 4, and 7 to ensure the integrity
> > +of the firmware and bootloaders. For PCR 8 and 9, a sophisticated tool is
> > +required to examine the GRUB configuration files and the files to be loaded
> > +to calculate the correct PCR values.
> > +
> > +Please note that PCRs are sensitive to any change, so an update of a component
> > +could invalidate the sealed key, and it is so-called PCR brittleness. For the
>
> , due to the so-called ..
>
Will fix it in the next version.
> > +bootloader update, PCR 4 may be affected. This can be mitigated by extracting
> > +the events from the TPM event log and predict the value with the updated
> > +bootloader binary. On the other hand, it is difficult to predict PCR 0~7 after
> > +a firmware update since the content of the code and the order of drivers may
> > +not follow the TPM event log from the previous firmware version, so it is
> > +necessary to reboot the system to update the measurement results of PCR 0~7
> > +and seal or sign the sealed key again.
> > +
> > +Reference: @url{https://uapi-group.org/specifications/specs/linux_tpm_pcr_registry/, Linux TPM PCR Registry}
> > +
> > +@subsection Setting up the extra disk key
> > +
> > +Instead of using the existing password, it is recommended to seal a new
> > +random disk key and use the existing password for recovery.
> > +
> > +Here are the sample commands to create a 128 random bytes key file and
> > +enroll the key into the target partition (sda2).
> > +
> > +@example
> > +# @kbd{dd if=/dev/urandom of=luks.key bs=1 count=128}
> > +# @kbd{cryptsetup luksAddKey /dev/sda2 luks.key --pbkdf=pbkdf2 --hash=sha512}
> > +@end example
> > +
> > +@subsection SRK mode
> > +
> > +To unlock the partition with SRK mode, assume that the sealed key is in
> > +@file{(hd0,gpt1)/boot/grub2/sealed.tpm}, the following GRUB commands
> > +unseal the disk key with SRK mode and supply it to @command{cryptomount}.
> > +
> > +@example
> > +@kbd{tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
> > +@kbd{cryptomount -u <UUID> -P tpm2}
> > +@end example
> > +
> > +There are two programs to create the sealed key for SRK mode: @command{grub-protect}
> > +and @command{pcr-oracle} (@url{https://github.com/okirch/pcr-oracle}).
> > +
> > +The following sample command uses @command{grub-protect} to seal the random
> > +key, @file{luks.key}, with PCR 0, 2, 4 and 7 in TPM 2.0 Key File format.
> > +
> > +@example
> > +@group
> > +# @kbd{grub-protect --action=add \
> > + --protector=tpm2 \
> > + --tpm2-pcrs=0,2,4,7 \
> > + --tpm2key \
> > + --tpm2-keyfile=luks.key \
> > + --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
> > +@end group
> > +@end example
> > +
> > +Since @command{grub-protect} only seals the key with the current PCR values,
> > +when a boot component updates such as shim or GRUB, it requires to reboot the
>
> @command{grub-protect} only seals the key with the current PCR values.
> Therefore, when a boot component, such as shim or GRUB, are updated, it is
> neccessary to reboot the system to update the measurement results and seal
> the key again.
>
ditto
> > +system to update the measurement results and seal the key again. That means
> > +the random disk key has to be stored in cleartext for the next key sealing.
> > +Besides, the measurement result of some PCRs may differ between boot time and
>
> Besides this, ...
>
ditto
> > +OS runtime. For example, PCR 9 measures the files loaded by GRUB including the
> > +linux kernel and initrd. To unlock the disk containing the kernel and initrd,
>
> s/linux/Linux
>
ditto
> > +the key has to be sealed with PCR 9 value before loading the kernel and
> > +initrd. However, PCR 9 changes after GRUB loading the kernel and initrd, so
> > +PCR 9 at OS runtime cannot be used directly for key sealing.
> > +
> > +To solve the problems, @command{pcr-oracle} takes a different approach. It
>
> s/the/these/
>
ditto
> > +reads the TPM eventlog and predicts the PCR values. Besides,
> > +@command{pcr-oracle} also supports ``authorized policy'' which allows the
> > +PCR policy to be updated with a valid signature, so that the user only
> > +needs to seal the random disk key once and then updates the signature
> > +of PCR policy for the later changes.
>
> ... and then the user needs to update the signature of the PCR policy for
> the later changes. (?)
>
> I am not sure what this means though in practice.
>
The random disk key is first sealed with the user's public key, and then
the user signs the 'policy', i.e. the hash of the PCR hashes, and
appends the signature into the key file as the parameter for
TPM2_PolicyAuthorize. For the later PCR changes, the user only
needs to sign the new policy and update the signature.
https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-tpm2_policyauthorize
How about rewriting the paragragh like this:
@command{pcr-oracle} also supports ``authorized policy'' which allows the
PCR policy to be updated with a valid signature, so that the user only seals
the random disk key once. For the later changes, the user just needs to
update the signature of PCR policy.
> > +
> > +To seal the key with authorized policy, the first thing is to generate
>
> the authorized policyt
>
Will fix it in the next version.
> > +the RSA policy key, @file{policy-key.pem}, and the authorized policy file,
> > +@file{authorized.policy}. In this example, PCR 0, 2, 4, 7 and 9 are chosen
> > +for key sealing.
> > +
> > +@example
> > +@group
> > +# @kbd{pcr-oracle --rsa-generate-key \
> > + --private-key policy-key.pem \
> > + --auth authorized.policy \
> > + create-authorized-policy 0,2,4,7,9}
> > +@end group
> > +@end example
> > +
> > +Then, we seal the random disk key, @file{luks.key}, with the authorized
> > +policy file and save the sealed key in @file{sealed.key}.
> > +
> > +@example
> > +@group
> > +# @kbd{pcr-oracle --key-format tpm2.0 \
> > + --auth authorized.policy \
> > + --input luks.key \
> > + --output sealed.key \
> > + seal-secret}
> > +@end group
> > +@end example
> > +
> > +The random disk key file, @file{luks.key}, now can be removed for good.
>
> Since we now have the sealed key we can now remove the random disk key file
> @file{lukes.key}.
>
ditto
> > +The last step is to sign the predicted PCR policy and save the final key
> > +file, @file{sealed.tpm}.
> > +
> > +@example
> > +@group
> > +# @kbd{pcr-oracle --key-format tpm2.0 \
> > + --private-key policy-key.pem \
> > + --from eventlog \
> > + --stop-event "grub-file=grub.cfg" \
> > + --after \
> > + --input sealed.key \
> > + --output /boot/efi/boot/grub2/sealed.tpm \
> > + sign 0,2,4,7,9}
> > +@end group
> > +@end example
> > +
> > +Here we also set a stop event for the prediction. With
> > +@kbd{--stop-event grub-file=grub.cfg --after}, @command{pcr-oracle} stops
> > +the calculation of PCR values right after GRUB loads @file{grub.cfg}.
> > +
> > +When shim or GRUB updates, it only requires to run the last @command{pcr-oracle}
> > +command to update the predicted PCR policy.
> > +
> > +@subsection NV index mode
> > +
> > +Instead of storing the sealed key in the file, NV index mode uses the TPM
>
> in a file
>
ditto
> > +non-volatile memory for the sealed key.
>
> to store the sealed key
>
ditto
> > +
> > +The following sample commands use tpm2-tools (@url{https://github.com/tpm2-software/tpm2-tools})
> > +commands to seal @file{luks.key} into the specific NV index: @kbd{0x81000000}.
> > +
> > +First, we need to create the object file for the primary key, i.e. storage
> > +root key (SRK) with the default key settings in GRUB: SHA256 hash algorithm
> > +and ECC key algorithm.
> > +
> > +@example
> > +# @kbd{tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx}
> > +@end example
> > +
> > +The next commands collect the current values of PCR 0, 2, 4, and 7 and saves
> > +them in @file{pcr.dat}.
> > +
> > +@example
> > +# @kbd{tpm2_startauthsession -S session.dat}
> > +# @kbd{tpm2_policypcr -S session.dat -l sha256:0,2,4,7 -f pcrs.dat -L policy.dat}
> > +# @kbd{tpm2_flushcontext session.dat}
> > +@end example
> > +
> > +The last commands seal @file{luks.key} with the primary key and stores the
> > +result in @kbd{0x81000000}.
> > +
> > +@example
> > +# @kbd{cat luks.key | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-}
> > +# @kbd{tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx}
> > +# @kbd{tpm2_evictcontrol -C o -c sealing.ctx 0x81000000}
> > +@end example
> > +
> > +To unseal the key, we have to specify the mode, @kbd{nv}, the NV index,
> > +@kbd{0x81000000}, and the PCRs, @kbd{0,2,4,7} for @command{tpm2_key_protector_init}
> > +command.
> > +
> > +@example
> > +@kbd{tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=0,2,4,7}
> > +@kbd{cryptomount -u <UUID> --protector tpm2}
> > +@end example
> > +
> > +@subsection Setting up software TPM for EMU platform
> > +
> > +In order to test TPM2 key protector and TPM2 Software Stack (TSS2), it is
> > +handy to set up a software TPM (swtpm) instance and run the commands on the
> > +EMU platform.
> > +
> > +Here are the commands to start a swtpm instance which provides a character
> > +device interface. To store the TPM states, the directory, @file{swtpm-state},
> > +is created before the @command{swtpm} command. All the messages are stored
> > +in @file{swtpm.log} including the name of the character device.
> > +
> > +@example
> > +# @kbd{mkdir swtpm-state}
> > +@group
> > +# @kbd{swtpm chardev --vtpm-proxy --tpmstate dir=swtpm-state \
> > + --tpm2 --ctrl type=unixio,path="swtpm-state/ctrl" \
> > + --flags startup-clear --daemon > swtpm.log}
> > +@end group
> > +@end example
> > +
> > +Then, we extract the name of the character device from @file{swtpm.log} and
> > +save it to the variable, @samp{tpm2dev}.
> > +
> > +@example
> > +# @kbd{tpm2dev=$(grep "New TPM device" swtpm.log | cut -d' ' -f 4)}
> > +@end example
> > +
> > +Now we can start @kbd{grub-emu} with @kbd{--tpm-device $tpm2dev} to interact
> > +with the swtpm instance.
> > +
> > +@example
> > +# @kbd{grub-emu --tpm-device $tpm2dev}
> > +@end example
> > +
> > +On the host, the tpm2-tools commands can interact with the swtpm instance by
> > +setting @samp{TPM2TOOLS_TCTI}.
> > +
> > +@example
> > +# @kbd{export TPM2TOOLS_TCTI="device:$tpm2dev"}
> > +@end example
> > +
> > +When the test is done, use @kbd{swtpm_ioctl} to send the shutdown
> > +command through the swtpm control channel.
> > +
> > +@example
> > +# @kbd{swtpm_ioctl -s --unix swtpm-state/ctrl}
> > +@end example
> > +
> > @node Platform limitations
> > @chapter Platform limitations
> > @@ -9211,6 +9553,7 @@ bootability on other machines.
> > * Invoking grub-mkrescue:: Make a GRUB rescue image
> > * Invoking grub-mount:: Mount a file system using GRUB
> > * Invoking grub-probe:: Probe device information for GRUB
> > +* Invoking grub-protect:: Protect a disk key with a key protector
> > * Invoking grub-script-check:: Check GRUB script file for syntax errors
> > @end menu
> > @@ -9593,6 +9936,170 @@ Print verbose messages.
> > @end table
> > +@node Invoking grub-protect
> > +@section Invoking grub-protect
> > +
> > +The program @command{grub-protect} protects a disk encryption key with
> > +a specified key protector.
> > +
> > +@table @option
> > +@item --help
> > +Print a summary of the command-line options and exit.
> > +
> > +@item --version
> > +Print the version number of GRUB and exit.
> > +
> > +@item -a
> > +@itemx --action=add|remove
> > +Add or remove a key protector to or from a key.
> > +
> > +@item -p
> > +@itemx --protector=@var{protector}
> > +Set the key protector. Currently, @samp{tpm2} is the only supported key
> > +protector.
> > +
> > +@item --tpm2-asymmetric=@var{type}
> > +Choose the the type of SRK. The valid options are @samp{RSA} (@samp{RSA2048})
> > +and @samp{ECC} (@samp{ECC_NIST_P256}).(default: @samp{ECC})
> > +
> > +@item --tpm2-bank=@var{alg}
> > +Choose bank of PCRs used to authorize key release: @samp{SHA1}, @samp{SHA256},
> > +@samp{SHA384}, or @samp{SHA512}. (default: @samp{SHA256})
> > +
> > +@item --tpm2-device=@var{device}
> > +Set the path to the TPM2 device. (default: @samp{/dev/tpm0})
> > +
> > +@item --tpm2-evict
> > +Evict a previously persisted SRK from the TPM, if any.
> > +
> > +@item --tpm2-keyfile=@var{file}
> > +Set the path to a file that contains the cleartext key to protect.
> > +
> > +@item --tpm2-outfile=@var{file}
> > +Set the path to the file that will contain the key after sealing
> > +(must be accessible to GRUB during boot).
> > +
> > +@item --tpm2-pcrs=@var{pcrs}
> > +Set a comma-separated list of PCRs used to authorize key release e.g., @samp{7,11}.
> > +Please be aware that PCR 0~7 are used by the firmware and the measurement result
> > +may change after a firmware update (for baremetal systems) or a package
> > +(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to the failure of key
> > +unsealing. (default: @samp{7})
> > +
> > +@item --tpm2-srk=@var{handle}
> > +Set the SRK handle, e.g. @samp{0x81000000}, if the SRK is to be made persistent.
> > +
> > +@item --tpm2key
> > +Use TPM 2.0 Key File format instead of the raw format.
>
> TPM 2.0 key file (?)
>
Hmmmm, then I have to update the help string of grub-protect either.
> > +
> > +@end table
> > +
> > +Before sealing the key, please check the TPM PCR usage
> > +(@pxref{TPM2 key protector, TPM PCR usage}) to choose a proper set of PCRs.
> > +
> > +Assume that there is a key file, @file{luks.key}, to be sealed with PCR 0, 2,
> > +4, and 7, here is the @command{grub-protect} command to create the sealed
>
> , then here ...
>
Will fix it in the next version.
> > +key file:
> > +
> > +@example
> > +@group
> > +# @kbd{grub-protect --action=add \
> > + --protector=tpm2 \
> > + --tpm2-pcrs=0,2,4,7 \
> > + --tpm2key \
> > + --tpm2-keyfile=luks.key \
> > + --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
> > +@end group
> > +@end example
> > +
> > +Then, GRUB can unlock the target partition with the following commands:
> > +
> > +@example
> > +@kbd{tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
> > +@kbd{cryptomount -u <UUID> -P tpm2}
> > +@end example
> > +
> > +In most of cases, the user only needs to create the key with the `add' action.
> > +If auto-unlocking is unwanted, just remove the file and restore the GRUB
> > +commands.
> > +
> > +The only case for the `remove' action is when the SRK is made persistent.
> > +
> > +There are two supported SRKs in @command{grub-protect}: @samp{RSA} and @samp{ECC}.
> > +Due to slower key generation, some users of the @samp{RSA} SRK would prefer
> > +making it persistent so that the TPM can skip the SRK generation when GRUB tries
> > +to unseal the key.
> > +
> > +The available persistent handles can be checked with @command{tpm2_getcap}.
> > +
> > +@example
> > +@group
> > +# @kbd{tpm2_getcap properties-variable}
> > +...
> > +TPM2_PT_HR_PERSISTENT: 0x0
> > +TPM2_PT_HR_PERSISTENT_AVAIL: 0x41
> > +...
> > +@end group
> > +@end example
> > +
> > +In this system, there is no persistent handle. A TPM handle is an unsigned
> > +32-bit integer, and the persistent handles starts with @samp{0x81}. Here
> > +we choose the well-known persistent handle: @samp{0x81000000}.
> > +
> > +@example
> > +@group
> > +# @kbd{grub-protect --action=add \
> > + --protector=tpm2 \
> > + --tpm2-pcrs=0,2,4,7 \
> > + --tpm2-asymmetric=RSA \
> > + --tpm2-srk=0x81000000 \
> > + --tpm2key \
> > + --tpm2-keyfile=luks.key \
> > + --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm}
> > +@end group
> > +@end example
> > +
> > +The additional @kbd{--tpm2-asymmetric=RSA} and @kbd{--tpm2-srk=0x81000000}
> > +options are used to make the key sealed with the RSA SRK and store the SRK
> > +in @samp{0x81000000}.
> > +
> > +For the @command{tpm2_key_protector_init} command, the additional @kbd{-s 0x81000000}
> > +informs the TPM2 key protector to fetch the SRK from @samp{0x81000000}.
> > +
> > +@example
> > +@kbd{tpm2_key_protector_init -s 0x81000000 --keyfile=(hd0,gpt1)/boot/grub2/sealed.tpm}
> > +@kbd{cryptomount -u <UUID> -P tpm2}
> > +@end example
> > +
> > +After making the SRK handle persistent, we can check the status of the
> > +persistent handles with @command{tpm2_getcap}.
> > +
> > +@example
> > +@group
> > +# @kbd{tpm2_getcap properties-variable}
> > +...
> > +TPM2_PT_HR_PERSISTENT: 0x1
> > +TPM2_PT_HR_PERSISTENT_AVAIL: 0x40
> > +...
> > +# @kbd{tpm2_getcap handles-persistent}
> > +- 0x81000000
> > +@end group
> > +@end example
> > +
> > +In case the user doesn't want to use the TPM2 key protector anymore, besides
> > +removing the sealed key file, here is the command to remove the persistent
>
> The sealed key can be remove once the user does not want to use the TPM2 key
> protector anymore. Here is the command to remove the persistent ...
>
ditto
> > +SRK handle (@samp{0x81000000}.) with @kbd{--tpm2-srk} and @kbd{--tpm2-evict}.
> > +
> > +@example
> > +@group
> > +# @kbd{grub-protect --action=remove \
> > + --protector=tpm2 \
> > + --tpm2-srk 0x81000000 \
> > + --tpm2-evict}
> > +@end group
> > +@end example
> > +
> > +
> > @node Invoking grub-script-check
> > @section Invoking grub-script-check
Really thanks for helping me improve this document.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 33/33] docs: Document TPM2 key protector
2024-09-20 8:16 ` Gary Lin via Grub-devel
@ 2024-09-20 13:42 ` Stefan Berger
2024-10-04 6:12 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Stefan Berger @ 2024-09-20 13:42 UTC (permalink / raw)
To: Gary Lin
Cc: The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On 9/20/24 4:16 AM, Gary Lin wrote:
> On Fri, Sep 13, 2024 at 10:25:14AM -0400, Stefan Berger wrote:
>>
>>
>>> +SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
>>> +
>>> +There are some options only available for the specific mode. The SRK-specific
>>> +options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
>>> +other hand, the NV index-specific option is @option{-n}.
>>> +
>>> +The key file for SRK mode can be supplied with either @option{-T} or
>>> +@option{-k}. The @option{-T} option is for the path to the key file in
>>> +the TPM 2.0 Key File format. Since the parameters for the TPM commands are
>>> +written in the policy sequences, there is no need to set the PCR
>>
>> What is 'the policy sequences' ?
>>
> It's the TPMPolicy sequence which contains the command code and the
> parameters.
So sequence is an ASN.1 sequence? 0x30 iirc. I think people will have a
hard time understanding this. You have to describe this in some other
way without the word 'policy sequence'.
>
> https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-tpmpolicy-syntax
>> When I looked through the patches I did not see anything particularly
>> related to EFI. Is it only available on EFI and EMU platforms because you
>> did not test it with a (Sea)BIOS for example ? I was actually going to try
>> it on PPC64 on KVM that has SLOF firmware.
>>
> It's related to the tcg2 functions defined in grub-core/lib/tss2/tcg2.h.
> Currently, there is only two implementations:
>
> EFI: grub-core/lib/efi/tcg2.c
> EMU: grub-core/lib/tss2/tcg2_emu.c
Right. I have a version of ieee1275 powerpc now.
>
>>> +reads the TPM eventlog and predicts the PCR values. Besides,
>>> +@command{pcr-oracle} also supports ``authorized policy'' which allows the
>>> +PCR policy to be updated with a valid signature, so that the user only
>>> +needs to seal the random disk key once and then updates the signature
>>> +of PCR policy for the later changes.
>>
>> ... and then the user needs to update the signature of the PCR policy for
>> the later changes. (?)
>>
>> I am not sure what this means though in practice.
>>
> The random disk key is first sealed with the user's public key, and then
> the user signs the 'policy', i.e. the hash of the PCR hashes, and
> appends the signature into the key file as the parameter for
> TPM2_PolicyAuthorize. For the later PCR changes, the user only
> needs to sign the new policy and update the signature.
>
> https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-tpm2_policyauthorize
>
> How about rewriting the paragragh like this:
>
> @command{pcr-oracle} also supports ``authorized policy'' which allows the
> PCR policy to be updated with a valid signature, so that the user only seals
> the random disk key once. For the later changes, the user just needs to
> update the signature of PCR policy.
You have to describe what you mean with 'the later changes'. Something
like this maybe:
If at some later time the PCR values change due to an updated of the
system's firmware, the user just need to ... ??
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support
2024-09-18 7:28 ` Gary Lin via Grub-devel
@ 2024-10-01 14:48 ` Daniel Kiper
2024-10-04 6:14 ` Gary Lin via Grub-devel
2024-10-07 6:06 ` Gary Lin via Grub-devel
0 siblings, 2 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-01 14:48 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On Wed, Sep 18, 2024 at 03:28:44PM +0800, Gary Lin via Grub-devel wrote:
> On Tue, Sep 17, 2024 at 11:14:33PM -0400, Stefan Berger wrote:
> > On 9/6/24 5:11 AM, Gary Lin wrote:
> > > A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to
> > > compose and submit TPM commands and parse reponses.
> > >
> >
> > > +static TPM_RC_t
> > > +tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG_t tag,
> > > + const TPM_CC_t commandCode,
> > > + TPM_RC_t *responseCode,
> > > + const struct grub_tpm2_buffer *in,
> > > + struct grub_tpm2_buffer *out)
> > > +{
> > > + grub_err_t err;
> > > + struct grub_tpm2_buffer buf;
> > > + TPMI_ST_COMMAND_TAG_t tag_out;
> > > + grub_uint32_t command_size;
> > > + grub_size_t max_output_size;
> > > +
> > > + /* Marshal */
> > > + grub_tpm2_buffer_init (&buf);
> > > + grub_tpm2_buffer_pack_u16 (&buf, tag);
> > > + grub_tpm2_buffer_pack_u32 (&buf, 0);
> > > + grub_tpm2_buffer_pack_u32 (&buf, commandCode);
> > > + grub_tpm2_buffer_pack (&buf, in->data, in->size);
> > > +
> > > + if (buf.error != 0)
> > > + return TPM_RC_FAILURE;
> > > +
> > > + command_size = grub_swap_bytes32 (buf.size);
> > > + grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size,
> > > + sizeof (command_size));
> >
> > This is odd. So UEFI requires that the command size is in little endian
> > while the TPM commands are typically all in big endian format? If so, could
> > you push this into the grub_tcg2_submit_command? Other firmware doesn't need
> > this odd endianess switch and could just leave the size as-is and just pass
> > the TPM command to the device without switching endianess again.
>
> EFI_TCG2_PROTOCOL.SubmitCommand() expects the little-endian
> InputParameterBlockSize, and InputParameterBlock in big-endian for the
> TPM command stream.
>
> Actually, the code is also needed when running grub-emu on a
> little-endian system. Maybe we can add an additional check for the
> endianness here and only run the code for the little-endian systems.
Why do not define grub_cpu_to_tpm32()/grub_tpm_to_cpu32() et consores
macros and make them noop on some archs?
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
` (33 preceding siblings ...)
2024-09-13 14:32 ` [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Stefan Berger
@ 2024-10-03 15:58 ` Daniel Kiper
2024-10-04 6:21 ` Gary Lin via Grub-devel
34 siblings, 1 reply; 82+ messages in thread
From: Daniel Kiper @ 2024-10-03 15:58 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:10:52PM +0800, Gary Lin via Grub-devel wrote:
> GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
>
> This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> Hernan Gatta to introduce the key protector framework and TPM2 stack
> to GRUB2, and this could be a useful feature for the systems to
> implement full disk encryption.
>
> To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> Daniel Axtens's "appended signature secure boot support" (*3) to import
> libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> 4.19.0 instead of 4.16.0 in the original patch.
I tried to build this patch set and got this errors:
./configure --target=i386 --with-platform=pc ...
make
...
tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative value [-Werror=shift-negative-value]
unsigned long num = ((long) GRUB_UINT_MAX) << 2;
^~
cc1: all warnings being treated as errors
May I ask you to test 32-bit builds, e.g. as above, before posting next
versions of patches?
I will send more comments in the following days. I will drop you a line
when you can repost the patch set.
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 04/33] libtasn1: replace strcat() with strcpy() in _asn1_str_cat()
2024-09-06 9:10 ` [PATCH v19 04/33] libtasn1: replace strcat() with strcpy() in _asn1_str_cat() Gary Lin via Grub-devel
@ 2024-10-03 16:03 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-03 16:03 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:10:56PM +0800, Gary Lin via Grub-devel wrote:
> strcat() is not available in GRUB. This commit replaces strcat() with
> strcpy() in _asn1_str_cat() as the preparation to replace other strcat()
> with the bounds-checking _asn1_str_cat().
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 05/33] libtasn1: replace strcat() with _asn1_str_cat()
2024-09-06 9:10 ` [PATCH v19 05/33] libtasn1: replace strcat() with _asn1_str_cat() Gary Lin via Grub-devel
@ 2024-10-03 16:06 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-03 16:06 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:10:57PM +0800, Gary Lin via Grub-devel wrote:
> strcat() is not available in GRUB. This commit replaces strcat() and
> _asn1_strcat() with the bounds-checking _asn1_str_cat().
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 06/33] libtasn1: adjust the header paths in libtasn1.h
2024-09-06 9:10 ` [PATCH v19 06/33] libtasn1: adjust the header paths in libtasn1.h Gary Lin via Grub-devel
@ 2024-10-03 16:08 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-03 16:08 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:10:58PM +0800, Gary Lin via Grub-devel wrote:
> Since libtasn1.h is the header to be included by users, including the
> standard POSIX headers in libtasn1.h would force the user to add the
> CFLAGS/CPPFLAGS for the POSIX headers.
>
> This commit adjusts the header paths to use the grub headers instead of
> the standard POSIX headers, so that users only need to include
> libtasn1.h to use libtasn1 functions.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 33/33] docs: Document TPM2 key protector
2024-09-20 13:42 ` Stefan Berger
@ 2024-10-04 6:12 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-04 6:12 UTC (permalink / raw)
To: Stefan Berger
Cc: Gary Lin, The development of GNU GRUB, Daniel Kiper, Hernan Gatta,
Daniel Axtens, shkhisti, jaskaran.khurana, christopher.co,
daniel.mihai, jaredz, development, jejb, mchang, patrick.colp,
Vladimir Serbinenko
On Fri, Sep 20, 2024 at 09:42:01AM -0400, Stefan Berger wrote:
>
Sorry for my late reply. Just back from vacation.
>
> On 9/20/24 4:16 AM, Gary Lin wrote:
> > On Fri, Sep 13, 2024 at 10:25:14AM -0400, Stefan Berger wrote:
> > >
> > >
>
> > > > +SHA1, SHA256, SHA384, and SHA512, and the default is SHA256.
> > > > +
> > > > +There are some options only available for the specific mode. The SRK-specific
> > > > +options are @option{-T}, @option{-k}, @option{-a}, and @option{-s}. On the
> > > > +other hand, the NV index-specific option is @option{-n}.
> > > > +
> > > > +The key file for SRK mode can be supplied with either @option{-T} or
> > > > +@option{-k}. The @option{-T} option is for the path to the key file in
> > > > +the TPM 2.0 Key File format. Since the parameters for the TPM commands are
> > > > +written in the policy sequences, there is no need to set the PCR
> > >
> > > What is 'the policy sequences' ?
> > >
> > It's the TPMPolicy sequence which contains the command code and the
> > parameters.
>
> So sequence is an ASN.1 sequence? 0x30 iirc. I think people will have a hard
> time understanding this. You have to describe this in some other way without
> the word 'policy sequence'.
>
I'm considering to replace 'policy sequence' with 'file'.
> >
> > https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-tpmpolicy-syntax
>
>
> > > When I looked through the patches I did not see anything particularly
> > > related to EFI. Is it only available on EFI and EMU platforms because you
> > > did not test it with a (Sea)BIOS for example ? I was actually going to try
> > > it on PPC64 on KVM that has SLOF firmware.
> > >
> > It's related to the tcg2 functions defined in grub-core/lib/tss2/tcg2.h.
> > Currently, there is only two implementations:
> >
> > EFI: grub-core/lib/efi/tcg2.c
> > EMU: grub-core/lib/tss2/tcg2_emu.c
>
> Right. I have a version of ieee1275 powerpc now.
>
> >
> > > > +reads the TPM eventlog and predicts the PCR values. Besides,
> > > > +@command{pcr-oracle} also supports ``authorized policy'' which allows the
> > > > +PCR policy to be updated with a valid signature, so that the user only
> > > > +needs to seal the random disk key once and then updates the signature
> > > > +of PCR policy for the later changes.
> > >
> > > ... and then the user needs to update the signature of the PCR policy for
> > > the later changes. (?)
> > >
> > > I am not sure what this means though in practice.
> > >
> > The random disk key is first sealed with the user's public key, and then
> > the user signs the 'policy', i.e. the hash of the PCR hashes, and
> > appends the signature into the key file as the parameter for
> > TPM2_PolicyAuthorize. For the later PCR changes, the user only
> > needs to sign the new policy and update the signature.
> >
> > https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html#name-tpm2_policyauthorize
> >
> > How about rewriting the paragragh like this:
> >
> > @command{pcr-oracle} also supports ``authorized policy'' which allows the
> > PCR policy to be updated with a valid signature, so that the user only seals
> > the random disk key once. For the later changes, the user just needs to
> > update the signature of PCR policy.
>
> You have to describe what you mean with 'the later changes'. Something like
> this maybe:
>
> If at some later time the PCR values change due to an updated of the
> system's firmware, the user just need to ... ??
It includes whatever changes to PCRs such as firmware update, bootloader
update, or config file update, so I'd extend the statement a bit:
If at some later time the PCR values change due to an update of the
system firmware, bootloader, or config file, the user just needs to ...
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support
2024-10-01 14:48 ` Daniel Kiper
@ 2024-10-04 6:14 ` Gary Lin via Grub-devel
2024-10-07 6:06 ` Gary Lin via Grub-devel
1 sibling, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-04 6:14 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On Tue, Oct 01, 2024 at 04:48:34PM +0200, Daniel Kiper wrote:
> On Wed, Sep 18, 2024 at 03:28:44PM +0800, Gary Lin via Grub-devel wrote:
> > On Tue, Sep 17, 2024 at 11:14:33PM -0400, Stefan Berger wrote:
> > > On 9/6/24 5:11 AM, Gary Lin wrote:
> > > > A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to
> > > > compose and submit TPM commands and parse reponses.
> > > >
> > >
> > > > +static TPM_RC_t
> > > > +tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG_t tag,
> > > > + const TPM_CC_t commandCode,
> > > > + TPM_RC_t *responseCode,
> > > > + const struct grub_tpm2_buffer *in,
> > > > + struct grub_tpm2_buffer *out)
> > > > +{
> > > > + grub_err_t err;
> > > > + struct grub_tpm2_buffer buf;
> > > > + TPMI_ST_COMMAND_TAG_t tag_out;
> > > > + grub_uint32_t command_size;
> > > > + grub_size_t max_output_size;
> > > > +
> > > > + /* Marshal */
> > > > + grub_tpm2_buffer_init (&buf);
> > > > + grub_tpm2_buffer_pack_u16 (&buf, tag);
> > > > + grub_tpm2_buffer_pack_u32 (&buf, 0);
> > > > + grub_tpm2_buffer_pack_u32 (&buf, commandCode);
> > > > + grub_tpm2_buffer_pack (&buf, in->data, in->size);
> > > > +
> > > > + if (buf.error != 0)
> > > > + return TPM_RC_FAILURE;
> > > > +
> > > > + command_size = grub_swap_bytes32 (buf.size);
> > > > + grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size,
> > > > + sizeof (command_size));
> > >
> > > This is odd. So UEFI requires that the command size is in little endian
> > > while the TPM commands are typically all in big endian format? If so, could
> > > you push this into the grub_tcg2_submit_command? Other firmware doesn't need
> > > this odd endianess switch and could just leave the size as-is and just pass
> > > the TPM command to the device without switching endianess again.
> >
> > EFI_TCG2_PROTOCOL.SubmitCommand() expects the little-endian
> > InputParameterBlockSize, and InputParameterBlock in big-endian for the
> > TPM command stream.
> >
> > Actually, the code is also needed when running grub-emu on a
> > little-endian system. Maybe we can add an additional check for the
> > endianness here and only run the code for the little-endian systems.
>
> Why do not define grub_cpu_to_tpm32()/grub_tpm_to_cpu32() et consores
> macros and make them noop on some archs?
>
This sounds a better solution. I'll work on that.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-10-03 15:58 ` Daniel Kiper
@ 2024-10-04 6:21 ` Gary Lin via Grub-devel
2024-10-17 18:05 ` Daniel Kiper
0 siblings, 1 reply; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-04 6:21 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Thu, Oct 03, 2024 at 05:58:41PM +0200, Daniel Kiper wrote:
> On Fri, Sep 06, 2024 at 05:10:52PM +0800, Gary Lin via Grub-devel wrote:
> > GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
> >
> > This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> > Hernan Gatta to introduce the key protector framework and TPM2 stack
> > to GRUB2, and this could be a useful feature for the systems to
> > implement full disk encryption.
> >
> > To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> > Daniel Axtens's "appended signature secure boot support" (*3) to import
> > libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> > 4.19.0 instead of 4.16.0 in the original patch.
>
> I tried to build this patch set and got this errors:
>
> ./configure --target=i386 --with-platform=pc ...
> make
> ...
> tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
> tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative value [-Werror=shift-negative-value]
> unsigned long num = ((long) GRUB_UINT_MAX) << 2;
> ^~
> cc1: all warnings being treated as errors
>
> May I ask you to test 32-bit builds, e.g. as above, before posting next
> versions of patches?
>
Sorry for that. Will do the 32-bit test build for the next version.
> I will send more comments in the following days. I will drop you a line
> when you can repost the patch set.
>
Okay.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 09/33] asn1_test: include asn1_test.h only
2024-09-06 9:11 ` [PATCH v19 09/33] asn1_test: include asn1_test.h only Gary Lin via Grub-devel
@ 2024-10-04 15:38 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-04 15:38 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:01PM +0800, Gary Lin via Grub-devel wrote:
> This commit removes all the headers and only uses asn1_test.h.
> To avoid including int.h from grub-core/lib/libtasn1-grub/lib/,
> CONST_DOWN is defined in reproducers.c.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 10/33] asn1_test: rename the main functions to the test names
2024-09-06 9:11 ` [PATCH v19 10/33] asn1_test: rename the main functions to the test names Gary Lin via Grub-devel
@ 2024-10-04 15:43 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-04 15:43 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:02PM +0800, Gary Lin via Grub-devel wrote:
> This commit changes the main functions in the testcases to the test
> names so that the real 'main' test function can invokes them.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 11/33] asn1_test: remove 'verbose' and the unnecessary printf()
2024-09-06 9:11 ` [PATCH v19 11/33] asn1_test: remove 'verbose' and the unnecessary printf() Gary Lin via Grub-devel
@ 2024-10-04 16:28 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-04 16:28 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:03PM +0800, Gary Lin via Grub-devel wrote:
> This commit removes the 'verbose' variables and the unnecessary printf()
> to simplify the output.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 12/33] asn1_test: print the error messages with grub_printf()
2024-09-06 9:11 ` [PATCH v19 12/33] asn1_test: print the error messages with grub_printf() Gary Lin via Grub-devel
@ 2024-10-04 16:31 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-04 16:31 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:04PM +0800, Gary Lin via Grub-devel wrote:
> This commit replaces printf() and fprintf() with grub_printf() to print
> the error messages for the testcases. Besides, asn1_strerror() is used
> to convert the result code to strings instead of asn1_perror().
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 13/33] asn1_test: return either 0 or 1 to reflect the results
2024-09-06 9:11 ` [PATCH v19 13/33] asn1_test: return either 0 or 1 to reflect the results Gary Lin via Grub-devel
@ 2024-10-04 16:34 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-04 16:34 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:05PM +0800, Gary Lin via Grub-devel wrote:
> Some testcases use exit() to end the test. Since all the asn1 testcases
> are invoked as functions, this commit replaces exit() with return to
> reflect the test results, so that the main test function can check the
> results.
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
I think this patch should go after #10.
But otherwise Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 14/33] asn1_test: use the grub-specific functions and types
2024-09-06 9:11 ` [PATCH v19 14/33] asn1_test: use the grub-specific functions and types Gary Lin via Grub-devel
@ 2024-10-04 16:36 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-04 16:36 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:06PM +0800, Gary Lin via Grub-devel wrote:
> This commit converts functions and types to the grub-specific ones:
>
> LONG_MAX -> GRUB_LONG_MAX
> INT_MAX -> GRUB_INT_MAX
> UINT_MAX -> GRUB_UINT_MAX
> size_t -> grub_size_t
> memcmp() -> grub_memcmp()
> memcpy() -> grub_memcpy()
> free() -> grub_free()
> strcmp() -> grub_strcmp()
>
> Signed-off-by: Daniel Axtens <dja@axtens.net>
> Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support
2024-10-01 14:48 ` Daniel Kiper
2024-10-04 6:14 ` Gary Lin via Grub-devel
@ 2024-10-07 6:06 ` Gary Lin via Grub-devel
1 sibling, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-07 6:06 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Vladimir Serbinenko
On Tue, Oct 01, 2024 at 04:48:34PM +0200, Daniel Kiper wrote:
> On Wed, Sep 18, 2024 at 03:28:44PM +0800, Gary Lin via Grub-devel wrote:
> > On Tue, Sep 17, 2024 at 11:14:33PM -0400, Stefan Berger wrote:
> > > On 9/6/24 5:11 AM, Gary Lin wrote:
> > > > A Trusted Platform Module (TPM) Software Stack (TSS) provides logic to
> > > > compose and submit TPM commands and parse reponses.
> > > >
> > >
> > > > +static TPM_RC_t
> > > > +tpm2_submit_command_real (const TPMI_ST_COMMAND_TAG_t tag,
> > > > + const TPM_CC_t commandCode,
> > > > + TPM_RC_t *responseCode,
> > > > + const struct grub_tpm2_buffer *in,
> > > > + struct grub_tpm2_buffer *out)
> > > > +{
> > > > + grub_err_t err;
> > > > + struct grub_tpm2_buffer buf;
> > > > + TPMI_ST_COMMAND_TAG_t tag_out;
> > > > + grub_uint32_t command_size;
> > > > + grub_size_t max_output_size;
> > > > +
> > > > + /* Marshal */
> > > > + grub_tpm2_buffer_init (&buf);
> > > > + grub_tpm2_buffer_pack_u16 (&buf, tag);
> > > > + grub_tpm2_buffer_pack_u32 (&buf, 0);
> > > > + grub_tpm2_buffer_pack_u32 (&buf, commandCode);
> > > > + grub_tpm2_buffer_pack (&buf, in->data, in->size);
> > > > +
> > > > + if (buf.error != 0)
> > > > + return TPM_RC_FAILURE;
> > > > +
> > > > + command_size = grub_swap_bytes32 (buf.size);
> > > > + grub_memcpy (&buf.data[sizeof (grub_uint16_t)], &command_size,
> > > > + sizeof (command_size));
> > >
> > > This is odd. So UEFI requires that the command size is in little endian
> > > while the TPM commands are typically all in big endian format? If so, could
> > > you push this into the grub_tcg2_submit_command? Other firmware doesn't need
> > > this odd endianess switch and could just leave the size as-is and just pass
> > > the TPM command to the device without switching endianess again.
> >
> > EFI_TCG2_PROTOCOL.SubmitCommand() expects the little-endian
> > InputParameterBlockSize, and InputParameterBlock in big-endian for the
> > TPM command stream.
> >
> > Actually, the code is also needed when running grub-emu on a
> > little-endian system. Maybe we can add an additional check for the
> > endianness here and only run the code for the little-endian systems.
>
> Why do not define grub_cpu_to_tpm32()/grub_tpm_to_cpu32() et consores
> macros and make them noop on some archs?
>
Actually I found that grub_cpu_to_be32() is sufficient here since TPM
expects big endian integers. grub_be_to_cpu16() and grub_be_to_cpu32()
are already used for buffer unpacking.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 22/33] key_protector: Add TPM2 Key Protector
2024-09-06 9:11 ` [PATCH v19 22/33] key_protector: Add TPM2 Key Protector Gary Lin via Grub-devel
2024-09-18 15:22 ` Stefan Berger
@ 2024-10-16 15:44 ` Daniel Kiper
2024-10-17 2:11 ` Gary Lin via Grub-devel
1 sibling, 1 reply; 82+ messages in thread
From: Daniel Kiper @ 2024-10-16 15:44 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:14PM +0800, Gary Lin via Grub-devel wrote:
> From: Hernan Gatta <hegatta@linux.microsoft.com>
>
> The TPM2 key protector is a module that enables the automatic retrieval
> of a fully-encrypted disk's unlocking key from a TPM 2.0.
>
> The theory of operation is such that the module accepts various
> arguments, most of which are optional and therefore possess reasonable
> defaults. One of these arguments is the keyfile/tpm2key parameter, which
> is mandatory. There are two supported key formats:
>
> 1. Raw Sealed Key (--keyfile)
> When sealing a key with TPM2_Create, the public portion of the sealed
> key is stored in TPM2B_PUBLIC, and the private portion is in
> TPM2B_PRIVATE. The raw sealed key glues the fully marshalled
> TPM2B_PUBLIC and TPM2B_PRIVATE into one file.
>
> 2. TPM 2.0 Key (--tpm2key)
> The following is the ASN.1 definition of TPM 2.0 Key File:
>
> TPMPolicy ::= SEQUENCE {
> CommandCode [0] EXPLICIT INTEGER
> CommandPolicy [1] EXPLICIT OCTET STRING
> }
>
> TPMAuthPolicy ::= SEQUENCE {
> Name [0] EXPLICIT UTF8STRING OPTIONAL
> Policy [1] EXPLICIT SEQUENCE OF TPMPolicy
> }
>
> TPMKey ::= SEQUENCE {
> type OBJECT IDENTIFIER
> emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL
> policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
> secret [2] EXPLICIT OCTET STRING OPTIONAL
> authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
> description [4] EXPLICIT UTF8String OPTIONAL,
> rsaParent [5] EXPLICIT BOOLEAN OPTIONAL,
> parent INTEGER
> pubkey OCTET STRING
> privkey OCTET STRING
> }
>
> The TPM2 key protector only expects a "sealed" key in DER encoding,
> so 'type' is always 2.23.133.10.1.5, 'emptyAuth' is 'TRUE', and
> 'secret' is empty. 'policy' and 'authPolicy' are the possible policy
> command sequences to construst the policy digest to unseal the key.
> Similar to the raw sealed key, the public portion (TPM2B_PUBLIC) of
> the sealed key is stored in 'pubkey', and the private portion
> (TPM2B_PRIVATE) is in 'privkey'.
>
> For more details: https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
>
> This sealed key file is created via the grub-protect tool. The tool
> utilizes the TPM's sealing functionality to seal (i.e., encrypt) an
> unlocking key using a Storage Root Key (SRK) to the values of various
> Platform Configuration Registers (PCRs). These PCRs reflect the state
> of the system as it boots. If the values are as expected, the system
> may be considered trustworthy, at which point the TPM allows for a
> caller to utilize the private component of the SRK to unseal (i.e.,
> decrypt) the sealed key file. The caller, in this case, is this key
> protector.
>
> The TPM2 key protector registers two commands:
>
> - tpm2_key_protector_init: Initializes the state of the TPM2 key
> protector for later usage, clearing any
> previous state, too, if any.
>
> - tpm2_key_protector_clear: Clears any state set by tpm2_key_protector_init.
>
> The way this is expected to be used requires the user to, either
> interactively or, normally, via a boot script, initialize/configure
> the key protector and then specify that it be used by the 'cryptomount'
> command (modifications to this command are in a different patch).
>
> For instance, to unseal the raw sealed key file:
>
> tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-1.key
> cryptomount -u <PART1_UUID> -P tpm2
>
> tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-2.key --pcrs=7,11
> cryptomount -u <PART2_UUID> -P tpm2
>
> Or, to unseal the TPM 2.0 Key file:
>
> tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-1.tpm
> cryptomount -u <PART1_UUID> -P tpm2
>
> tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-2.tpm --pcrs=7,11
> cryptomount -u <PART2_UUID> -P tpm2
>
> If a user does not initialize the key protector and attempts to use it
> anyway, the protector returns an error.
>
> Before unsealing the key, the TPM2 key protector follows the "TPMPolicy"
> sequences to enforce the TPM policy commands to construct a valid policy
> digest to unseal the key.
>
> For the TPM 2.0 Key files, 'authPolicy' may contain multiple "TPMPolicy"
> sequences, the TPM2 key protector iterates 'authPolicy' to find a valid
> sequence to unseal key. If 'authPolicy' is empty or all sequences in
> 'authPolicy' fail, the protector tries the one from 'policy'. In case
> 'policy' is also empty, the protector creates a "TPMPolicy" sequence
> based on the given PCR selection.
>
> For the raw sealed key, the TPM2 key protector treats the key file as a
> TPM 2.0 Key file without 'authPolicy' and 'policy', so the "TPMPolicy"
> sequence is always based on the PCR selection from the command
> parameters.
>
> This commit only supports one policy command: TPM2_PolicyPCR. The
> command set will be extended to support advanced features, such as
> authorized policy, in the later commits.
>
> Cc: Stefan Berger <stefanb@linux.ibm.com>
> Cc: James Bottomley <jejb@linux.ibm.com>
> Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
> grub-core/Makefile.core.def | 11 +
> grub-core/commands/tpm2_key_protector/args.c | 129 ++
> .../commands/tpm2_key_protector/module.c | 1153 +++++++++++++++++
> grub-core/commands/tpm2_key_protector/tpm2.h | 36 +
> .../commands/tpm2_key_protector/tpm2_args.h | 49 +
> .../commands/tpm2_key_protector/tpm2key.asn | 49 +
> .../commands/tpm2_key_protector/tpm2key.c | 499 +++++++
> .../commands/tpm2_key_protector/tpm2key.h | 87 ++
> .../tpm2_key_protector/tpm2key_asn1_tab.c | 63 +
> 9 files changed, 2076 insertions(+)
> create mode 100644 grub-core/commands/tpm2_key_protector/args.c
> create mode 100644 grub-core/commands/tpm2_key_protector/module.c
> create mode 100644 grub-core/commands/tpm2_key_protector/tpm2.h
> create mode 100644 grub-core/commands/tpm2_key_protector/tpm2_args.h
> create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.asn
> create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.c
> create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.h
> create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c
>
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 45b705a34..97ae4e49b 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -2578,6 +2578,17 @@ module = {
> cppflags = '-I$(srcdir)/lib/tss2';
> };
>
> +module = {
> + name = tpm2_key_protector;
> + common = commands/tpm2_key_protector/args.c;
> + common = commands/tpm2_key_protector/module.c;
> + common = commands/tpm2_key_protector/tpm2key.c;
> + common = commands/tpm2_key_protector/tpm2key_asn1_tab.c;
> + /* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */
> + enable = efi;
> + cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub';
> +};
> +
> module = {
> name = tr;
> common = commands/tr.c;
> diff --git a/grub-core/commands/tpm2_key_protector/args.c b/grub-core/commands/tpm2_key_protector/args.c
> new file mode 100644
> index 000000000..c58cbe307
> --- /dev/null
> +++ b/grub-core/commands/tpm2_key_protector/args.c
> @@ -0,0 +1,129 @@
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2022 Microsoft Corporation
> + * Copyright (C) 2024 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 "tpm2_args.h"
> +
> +grub_err_t
> +grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs,
> + grub_uint8_t *pcr_count)
> +{
> + char *current_pcr = value;
> + char *next_pcr;
> + const char *pcr_end;
> + grub_uint64_t pcr;
> + grub_uint8_t i;
> +
> + if (grub_strlen (value) == 0)
> + return GRUB_ERR_BAD_ARGUMENT;
> +
> + *pcr_count = 0;
> + for (i = 0; i < TPM_MAX_PCRS; i++)
> + {
> + next_pcr = grub_strchr (current_pcr, ',');
> + if (next_pcr == current_pcr)
> + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Empty entry in PCR list");
> + if (next_pcr != NULL)
> + *next_pcr = '\0';
> +
> + grub_errno = GRUB_ERR_NONE;
This is probably remnant from previous version of the patch.
> + pcr = grub_strtoul (current_pcr, &pcr_end, 10);
> + if (*current_pcr == '\0' || *pcr_end != '\0')
> + return grub_error (GRUB_ERR_BAD_NUMBER, "Entry '%s' in PCR list is not a number", current_pcr);
> +
> + if (pcr > TPM_MAX_PCRS)
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Entry %" PRIuGRUB_UINT64_T " in PCR list is too large to be a PCR number, PCR numbers range from 0 to %u", pcr, TPM_MAX_PCRS);
> +
> + pcrs[i] = (grub_uint8_t) pcr;
> + ++(*pcr_count);
> +
> + if (next_pcr == NULL)
> + break;
> +
> + current_pcr = next_pcr + 1;
> + if (*current_pcr == '\0')
> + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Trailing comma at the end of PCR list");
> + }
> +
> + if (i == TPM_MAX_PCRS)
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Too many PCRs in PCR list, the maximum number of PCRs is %u", TPM_MAX_PCRS);
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +grub_err_t
> +grub_tpm2_protector_parse_asymmetric (const char *value,
> + grub_srk_type_t *srk_type)
> +{
> + if (grub_strcasecmp (value, "ECC") == 0 ||
> + grub_strcasecmp (value, "ECC_NIST_P256") == 0)
> + {
> + srk_type->type = TPM_ALG_ECC;
> + srk_type->detail.ecc_curve = TPM_ECC_NIST_P256;
> + }
> + else if (grub_strcasecmp (value, "RSA") == 0 ||
> + grub_strcasecmp (value, "RSA2048") == 0)
> + {
> + srk_type->type = TPM_ALG_RSA;
> + srk_type->detail.rsa_bits = 2048;
> + }
> + else
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid asymmetric key type", value);
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +grub_err_t
> +grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID_t *bank)
> +{
> + if (grub_strcasecmp (value, "SHA1") == 0)
> + *bank = TPM_ALG_SHA1;
> + else if (grub_strcasecmp (value, "SHA256") == 0)
> + *bank = TPM_ALG_SHA256;
> + else if (grub_strcasecmp (value, "SHA384") == 0)
> + *bank = TPM_ALG_SHA384;
> + else if (grub_strcasecmp (value, "SHA512") == 0)
> + *bank = TPM_ALG_SHA512;
> + else
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid PCR bank", value);
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +grub_err_t
> +grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle)
> +{
> + grub_uint64_t num;
> + const char *str_end;
> +
> + grub_errno = GRUB_ERR_NONE;
Ditto. Please fix similar problems everywhere...
> + num = grub_strtoul (value, &str_end, 0);
> + if (*value == '\0' || *str_end != '\0')
> + return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is not a number", value);
> +
> + if (num > GRUB_UINT_MAX)
> + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
> +
> + *handle = (TPM_HANDLE_t) num;
> +
> + return GRUB_ERR_NONE;
> +}
> diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
> new file mode 100644
> index 000000000..909c3cc6a
> --- /dev/null
> +++ b/grub-core/commands/tpm2_key_protector/module.c
> @@ -0,0 +1,1153 @@
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2022 Microsoft Corporation
> + * Copyright (C) 2024 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/extcmd.h>
> +#include <grub/file.h>
> +#include <grub/list.h>
> +#include <grub/misc.h>
> +#include <grub/mm.h>
> +#include <grub/key_protector.h>
> +
> +#include <tss2_buffer.h>
> +#include <tss2_types.h>
> +#include <tss2_mu.h>
> +
> +#include "tpm2_args.h"
> +#include "tpm2.h"
> +#include "tpm2key.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +typedef enum grub_tpm2_protector_mode
> +{
> + GRUB_TPM2_PROTECTOR_MODE_UNSET,
> + GRUB_TPM2_PROTECTOR_MODE_SRK,
> + GRUB_TPM2_PROTECTOR_MODE_NV
> +} grub_tpm2_protector_mode_t;
> +
> +enum grub_tpm2_protector_options
> +{
> + OPTION_MODE,
> + OPTION_PCRS,
> + OPTION_BANK,
> + OPTION_TPM2KEY,
> + OPTION_KEYFILE,
> + OPTION_SRK,
> + OPTION_ASYMMETRIC,
> + OPTION_NVINDEX
> +};
May I ask you to be more consistent and define enums
as types like you did for grub_tpm2_protector_mode?
And again, you can drop "grub_" prefixes from all stuff which is
internal for a given C file.
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 24/33] util/grub-protect: Add new tool
2024-09-06 9:11 ` [PATCH v19 24/33] util/grub-protect: Add new tool Gary Lin via Grub-devel
@ 2024-10-16 16:04 ` Daniel Kiper
2024-10-17 2:39 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Daniel Kiper @ 2024-10-16 16:04 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:16PM +0800, Gary Lin via Grub-devel wrote:
> From: Hernan Gatta <hegatta@linux.microsoft.com>
>
> To utilize the key protectors framework, there must be a way to protect
> full-disk encryption keys in the first place. The grub-protect tool
> includes support for the TPM2 key protector but other protectors that
> require setup ahead of time can be supported in the future.
>
> For the TPM2 key protector, the intended flow is for a user to have a
> LUKS 1 or LUKS 2-protected fully-encrypted disk. The user then creates a
> new LUKS key file, say by reading /dev/urandom into a file, and creates
> a new LUKS key slot for this key. Then, the user invokes the grub-protect
> tool to seal this key file to a set of PCRs using the system's TPM 2.0.
> The resulting sealed key file is stored in an unencrypted partition such
> as the EFI System Partition (ESP) so that GRUB may read it. The user also
> has to ensure the cryptomount command is included in GRUB's boot script
> and that it carries the requisite key protector (-P) parameter.
>
> Sample usage:
>
> $ dd if=/dev/urandom of=luks-key bs=1 count=32
> $ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2 --hash=sha512
>
> To seal the key with TPM 2.0 Key File (recommended):
>
> $ sudo grub-protect --action=add \
> --protector=tpm2 \
> --tpm2-pcrs=0,2,4,7,9 \
Please replace tabs with spaces here...
> --tpm2key \
> --tpm2-keyfile=luks-key \
> --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm
>
> Or, to seal the key with the raw sealed key:
>
> $ sudo grub-protect --action=add \
> --protector=tpm2 \
> --tpm2-pcrs=0,2,4,7,9 \
Ditto...
> --tpm2-keyfile=luks-key \
> --tpm2-outfile=/boot/efi/boot/grub2/sealed.key
>
> Then, in the boot script, for TPM 2.0 Key File:
>
> tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
> cryptomount -u <SDB1_UUID> -P tpm2
>
> Or, for the raw sealed key:
>
> tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.key --pcrs=0,2,4,7,9
> cryptomount -u <SDB1_UUID> -P tpm2
>
> The benefit of using TPM 2.0 Key File is that the PCR set is already
> written in the key file, so there is no need to specify PCRs when
> invoking tpm2_key_protector_init.
>
> Cc: Stefan Berger <stefanb@linux.ibm.com>
> Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> ---
> .gitignore | 2 +
> Makefile.util.def | 26 +
> configure.ac | 30 +
> docs/man/grub-protect.h2m | 4 +
> util/grub-protect.c | 1394 +++++++++++++++++++++++++++++++++++++
> 5 files changed, 1456 insertions(+)
> create mode 100644 docs/man/grub-protect.h2m
> create mode 100644 util/grub-protect.c
>
> diff --git a/.gitignore b/.gitignore
> index 4c1f91db8..2105d87c8 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -169,6 +169,8 @@ widthspec.bin
> /grub-ofpathname.exe
> /grub-probe
> /grub-probe.exe
> +/grub-protect
> +/grub-protect.exe
> /grub-reboot
> /grub-render-label
> /grub-render-label.exe
> diff --git a/Makefile.util.def b/Makefile.util.def
> index fb82f59a0..074c0aff7 100644
> --- a/Makefile.util.def
> +++ b/Makefile.util.def
> @@ -208,6 +208,32 @@ program = {
> ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
> };
>
> +program = {
> + name = grub-protect;
> + mansection = 1;
> +
> + common = grub-core/kern/emu/argp_common.c;
> + common = grub-core/osdep/init.c;
> + common = grub-core/lib/tss2/buffer.c;
> + common = grub-core/lib/tss2/tss2_mu.c;
> + common = grub-core/lib/tss2/tpm2_cmd.c;
> + common = grub-core/commands/tpm2_key_protector/args.c;
> + common = grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c;
> + common = util/grub-protect.c;
> + common = util/probe.c;
> +
> + 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 = grub-core/lib/gnulib/libgnu.a;
> + ldadd = '$(LIBTASN1)';
> + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
> +
> + condition = COND_GRUB_PROTECT;
> +};
> +
> program = {
> name = grub-mkrelpath;
> mansection = 1;
> diff --git a/configure.ac b/configure.ac
> index 458b8382b..ad1e7bea5 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -76,6 +76,7 @@ grub_TRANSFORM([grub-mkpasswd-pbkdf2])
> grub_TRANSFORM([grub-mkrelpath])
> grub_TRANSFORM([grub-mkrescue])
> grub_TRANSFORM([grub-probe])
> +grub_TRANSFORM([grub-protect])
> grub_TRANSFORM([grub-reboot])
> grub_TRANSFORM([grub-script-check])
> grub_TRANSFORM([grub-set-default])
> @@ -2068,6 +2069,29 @@ fi
> AC_SUBST([LIBZFS])
> AC_SUBST([LIBNVPAIR])
>
> +AC_ARG_ENABLE([grub-protect],
> + [AS_HELP_STRING([--enable-grub-protect],
> + [build and install the `grub-protect' utility (default=guessed)])])
> +if test x"$enable_grub_protect" = xno ; then
> + grub_protect_excuse="explicitly disabled"
> +fi
> +
> +LIBTASN1=
> +if test x"$grub_protect_excuse" = x ; then
> + AC_CHECK_LIB([tasn1], [asn1_write_value], [LIBTASN1="-ltasn1"], [grub_protect_excuse="need libtasn1 library"])
> +fi
> +AC_SUBST([LIBTASN1])
> +
> +if test x"$enable_grub_protect" = xyes && test x"$grub_protect_excuse" != x ; then
> + AC_MSG_ERROR([grub-protect was explicitly requested but can't be compiled ($grub_protect_excuse)])
> +fi
> +if test x"$grub_protect_excuse" = x ; then
> +enable_grub_protect=yes
> +else
> +enable_grub_protect=no
> +fi
> +AC_SUBST([enable_grub_protect])
> +
> LIBS=""
>
> AC_SUBST([FONT_SOURCE])
> @@ -2184,6 +2208,7 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes])
> AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes])
> AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes])
> AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes])
> +AM_CONDITIONAL([COND_GRUB_PROTECT], [test x$enable_grub_protect = xyes])
> AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x])
> if test x$FONT_SOURCE != x ; then
> HAVE_FONT_SOURCE=1
> @@ -2311,6 +2336,11 @@ echo grub-mount: Yes
> else
> echo grub-mount: No "($grub_mount_excuse)"
> fi
> +if [ x"$grub_protect_excuse" = x ]; then
> +echo grub-protect: Yes
> +else
> +echo grub-protect: No "($grub_protect_excuse)"
> +fi
> if [ x"$starfield_excuse" = x ]; then
> echo starfield theme: Yes
> echo With DejaVuSans font from $DJVU_FONT_SOURCE
> diff --git a/docs/man/grub-protect.h2m b/docs/man/grub-protect.h2m
> new file mode 100644
> index 000000000..ecf1c9eab
> --- /dev/null
> +++ b/docs/man/grub-protect.h2m
> @@ -0,0 +1,4 @@
> +[NAME]
> +grub-protect \- protect a disk key with a key protector
> +[DESCRIPTION]
> +grub-protect helps to protect a disk encryption key with a specified key protector.
> diff --git a/util/grub-protect.c b/util/grub-protect.c
> new file mode 100644
> index 000000000..fb4ea4079
> --- /dev/null
> +++ b/util/grub-protect.c
> @@ -0,0 +1,1394 @@
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2022 Microsoft Corporation
> + * Copyright (C) 2023 SUSE LLC
> + * Copyright (C) 2024 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 <config.h>
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <libtasn1.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +#include <grub/emu/hostdisk.h>
> +#include <grub/emu/misc.h>
> +
> +#include <grub/util/misc.h>
> +
> +#include <tss2_buffer.h>
> +#include <tss2_mu.h>
> +#include <tcg2.h>
> +#include <tpm2_args.h>
> +#include <tpm2.h>
> +
> +#pragma GCC diagnostic ignored "-Wmissing-prototypes"
> +#pragma GCC diagnostic ignored "-Wmissing-declarations"
> +#include <argp.h>
> +#pragma GCC diagnostic error "-Wmissing-prototypes"
> +#pragma GCC diagnostic error "-Wmissing-declarations"
> +
> +#include "progname.h"
> +
> +/* Unprintable option keys for argp */
> +typedef enum grub_protect_opt
> +{
> + /* General */
> + GRUB_PROTECT_OPT_ACTION = 'a',
> + GRUB_PROTECT_OPT_PROTECTOR = 'p',
> + /* TPM2 */
> + GRUB_PROTECT_OPT_TPM2_DEVICE = 0x100,
> + GRUB_PROTECT_OPT_TPM2_PCRS,
> + GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
> + GRUB_PROTECT_OPT_TPM2_BANK,
> + GRUB_PROTECT_OPT_TPM2_SRK,
> + GRUB_PROTECT_OPT_TPM2_KEYFILE,
> + GRUB_PROTECT_OPT_TPM2_OUTFILE,
> + GRUB_PROTECT_OPT_TPM2_EVICT,
> + GRUB_PROTECT_OPT_TPM2_TPM2KEY
> +} grub_protect_opt;
Again, you can drop "grub_" prefixes for internal stuff...
> +/* Option flags to keep track of specified arguments */
> +typedef enum grub_protect_arg
> +{
> + /* General */
> + GRUB_PROTECT_ARG_ACTION = 1 << 0,
> + GRUB_PROTECT_ARG_PROTECTOR = 1 << 1,
> + /* TPM2 */
> + GRUB_PROTECT_ARG_TPM2_DEVICE = 1 << 2,
> + GRUB_PROTECT_ARG_TPM2_PCRS = 1 << 3,
> + GRUB_PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4,
> + GRUB_PROTECT_ARG_TPM2_BANK = 1 << 5,
> + GRUB_PROTECT_ARG_TPM2_SRK = 1 << 6,
> + GRUB_PROTECT_ARG_TPM2_KEYFILE = 1 << 7,
> + GRUB_PROTECT_ARG_TPM2_OUTFILE = 1 << 8,
> + GRUB_PROTECT_ARG_TPM2_EVICT = 1 << 9,
> + GRUB_PROTECT_ARG_TPM2_TPM2KEY = 1 << 10
> +} grub_protect_arg_t;
Ditto and in other patches too...
> +typedef enum grub_protect_protector
> +{
> + GRUB_PROTECT_TYPE_ERROR,
> + GRUB_PROTECT_TYPE_TPM2
> +} grub_protect_protector_t;
> +
> +typedef enum grub_protect_action
> +{
> + GRUB_PROTECT_ACTION_ERROR,
> + GRUB_PROTECT_ACTION_ADD,
> + GRUB_PROTECT_ACTION_REMOVE
> +} grub_protect_action_t;
> +
> +struct grub_protect_args
> +{
> + grub_protect_arg_t args;
> + grub_protect_action_t action;
> + grub_protect_protector_t protector;
> +
> + const char *tpm2_device;
> + grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS];
> + grub_uint8_t tpm2_pcr_count;
> + grub_srk_type_t srk_type;
> + TPM_ALG_ID_t tpm2_bank;
> + TPM_HANDLE_t tpm2_srk;
> + const char *tpm2_keyfile;
> + const char *tpm2_outfile;
> + int tpm2_evict;
> + int tpm2_tpm2key;
> +};
> +
> +static struct argp_option grub_protect_options[] =
> + {
> + /* Top-level options */
> + {
> + .name = "action",
> + .key = 'a',
> + .arg = "add|remove",
> + .flags = 0,
> + .doc =
> + N_("Add or remove a key protector to or from a key."),
> + .group = 0
> + },
> + {
> + .name = "protector",
> + .key = 'p',
> + .arg = "tpm2",
> + .flags = 0,
> + .doc =
> + N_("Set key protector to use (only tpm2 is currently supported)."),
> + .group = 0
> + },
> + /* TPM2 key protector options */
> + {
> + .name = "tpm2-device",
> + .key = GRUB_PROTECT_OPT_TPM2_DEVICE,
> + .arg = "FILE",
> + .flags = 0,
> + .doc =
> + N_("Set the path to the TPM2 device. (default: /dev/tpm0)"),
> + .group = 0
> + },
> + {
> + .name = "tpm2-pcrs",
> + .key = GRUB_PROTECT_OPT_TPM2_PCRS,
> + .arg = "0[,1]...",
> + .flags = 0,
> + .doc =
> + N_("Set a comma-separated list of PCRs used to authorize key release "
> + "e.g., '7,11'. Please be aware that PCR 0~7 are used by the "
> + "firmware and the measurement result may change after a "
> + "firmware update (for baremetal systems) or a package "
> + "(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to "
> + "the failure of key unsealing. (default: 7)"),
> + .group = 0
> + },
> + {
> + .name = "tpm2-bank",
> + .key = GRUB_PROTECT_OPT_TPM2_BANK,
> + .arg = "ALG",
> + .flags = 0,
> + .doc =
> + N_("Set the bank of PCRs used to authorize key release: "
> + "SHA1, SHA256, SHA384, or SHA512. (default: SHA256)"),
> + .group = 0
> + },
> + {
> + .name = "tpm2-keyfile",
> + .key = GRUB_PROTECT_OPT_TPM2_KEYFILE,
> + .arg = "FILE",
> + .flags = 0,
> + .doc =
> + N_("Set the path to a file that contains the cleartext key to protect."),
> + .group = 0
> + },
> + {
> + .name = "tpm2-outfile",
> + .key = GRUB_PROTECT_OPT_TPM2_OUTFILE,
> + .arg = "FILE",
> + .flags = 0,
> + .doc =
> + N_("Set the path to the file that will contain the key after sealing "
> + "(must be accessible to GRUB during boot)."),
> + .group = 0
> + },
> + {
> + .name = "tpm2-srk",
> + .key = GRUB_PROTECT_OPT_TPM2_SRK,
> + .arg = "NUM",
> + .flags = 0,
> + .doc =
> + N_("Set the SRK handle if the SRK is to be made persistent."),
> + .group = 0
> + },
> + {
> + .name = "tpm2-asymmetric",
> + .key = GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
> + .arg = "TYPE",
> + .flags = 0,
> + .doc =
> + N_("Set the type of SRK: RSA (RSA2048) and ECC (ECC_NIST_P256)."
> + "(default: ECC)"),
> + .group = 0
> + },
> + {
> + .name = "tpm2-evict",
> + .key = GRUB_PROTECT_OPT_TPM2_EVICT,
> + .arg = NULL,
> + .flags = 0,
> + .doc =
> + N_("Evict a previously persisted SRK from the TPM, if any."),
> + .group = 0
> + },
> + {
> + .name = "tpm2key",
> + .key = GRUB_PROTECT_OPT_TPM2_TPM2KEY,
> + .arg = NULL,
> + .flags = 0,
> + .doc =
> + N_("Use TPM 2.0 Key File format instead of the raw format."),
> + .group = 0
> + },
> + /* End of list */
> + { 0, 0, 0, 0, 0, 0 }
> + };
> +
> +static int protector_tpm2_fd = -1;
> +
> +static grub_err_t
> +protect_read_file (const char *filepath, void **buffer, size_t *buffer_size)
> +{
> + grub_err_t err;
> + FILE *f;
> + long len;
> + void *buf;
> +
> + f = fopen (filepath, "rb");
> + if (f == NULL)
> + return GRUB_ERR_FILE_NOT_FOUND;
> +
> + if (fseek (f, 0, SEEK_END))
> + {
> + err = GRUB_ERR_FILE_READ_ERROR;
> + goto exit1;
> + }
> +
> + len = ftell (f);
> + if (len <= 0)
> + {
> + err = GRUB_ERR_FILE_READ_ERROR;
> + goto exit1;
> + }
> +
> + rewind (f);
> +
> + buf = grub_malloc (len);
> + if (buf == NULL)
> + {
> + err = GRUB_ERR_OUT_OF_MEMORY;
> + goto exit1;
> + }
> +
> + if (fread (buf, len, 1, f) != 1)
> + {
> + err = GRUB_ERR_FILE_READ_ERROR;
> + goto exit2;
> + }
> +
> + *buffer = buf;
> + *buffer_size = len;
> +
> + buf = NULL;
> + err = GRUB_ERR_NONE;
> +
> + exit2:
> + grub_free (buf);
> +
> + exit1:
> + fclose (f);
> +
> + return err;
> +}
> +
> +static grub_err_t
> +protect_write_file (const char *filepath, void *buffer, size_t buffer_size)
> +{
> + grub_err_t err;
> + FILE *f;
> +
> + f = fopen (filepath, "wb");
> + if (f == NULL)
> + return GRUB_ERR_FILE_NOT_FOUND;
> +
> + if (fwrite (buffer, buffer_size, 1, f) != 1)
> + {
> + err = GRUB_ERR_WRITE_ERROR;
> + goto exit1;
s/exit1/exit/
> + }
> +
> + err = GRUB_ERR_NONE;
> +
> + exit1:
> + fclose (f);
> +
> + return err;
> +}
> +
> +grub_err_t
> +grub_tcg2_get_max_output_size (grub_size_t *size)
This function seems unused.
> +{
> + if (size == NULL)
> + return GRUB_ERR_BAD_ARGUMENT;
> +
> + *size = GRUB_TPM2_BUFFER_CAPACITY;
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +grub_err_t
> +grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
> + grub_size_t output_size, grub_uint8_t *output)
Ditto...
> +{
> + static const grub_size_t header_size = sizeof (grub_uint16_t) +
> + (2 * sizeof(grub_uint32_t));
> +
> + if (write (protector_tpm2_fd, input, input_size) != input_size)
> + return GRUB_ERR_BAD_DEVICE;
> +
> + if (read (protector_tpm2_fd, output, output_size) < header_size)
> + return GRUB_ERR_BAD_DEVICE;
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +static grub_err_t
> +protect_tpm2_open_device (const char *dev_node)
> +{
> + if (protector_tpm2_fd != -1)
> + return GRUB_ERR_NONE;
> +
> + protector_tpm2_fd = open (dev_node, O_RDWR);
> + if (protector_tpm2_fd == -1)
> + {
> + fprintf (stderr, "Could not open TPM device (%s).\n", strerror (errno));
> + return GRUB_ERR_FILE_NOT_FOUND;
> + }
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +static grub_err_t
> +protect_tpm2_close_device (void)
> +{
> + int err;
> +
> + if (protector_tpm2_fd == -1)
> + return GRUB_ERR_NONE;
> +
> + err = close (protector_tpm2_fd);
> + if (err != GRUB_ERR_NONE)
> + {
> + fprintf (stderr, "Could not close TPM device (Error: %u).\n", errno);
> + return GRUB_ERR_IO;
> + }
> +
> + protector_tpm2_fd = -1;
> + return GRUB_ERR_NONE;
> +}
> +
> +static grub_err_t
> +protect_tpm2_get_policy_digest (struct grub_protect_args *args, TPM2B_DIGEST_t *digest)
> +{
> + TPM_RC_t rc;
> + TPML_PCR_SELECTION_t pcr_sel = {
> + .count = 1,
> + .pcrSelections = {
> + {
> + .hash = args->tpm2_bank,
> + .sizeOfSelect = 3,
> + .pcrSelect = { 0 }
> + },
> + }
> + };
> + TPML_PCR_SELECTION_t pcr_sel_out = { 0 };
Redundant spaces around 0.
> + TPML_DIGEST_t pcr_values = { 0 };
Ditto and below...
> + TPM2B_DIGEST_t pcr_digest = { 0 };
> + grub_size_t pcr_digest_len;
> + TPM2B_MAX_BUFFER_t pcr_concat = { 0 };
> + grub_size_t pcr_concat_len;
> + grub_uint8_t *pcr_cursor;
> + TPM2B_NONCE_t nonce = { 0 };
> + TPM2B_ENCRYPTED_SECRET_t salt = { 0 };
> + TPMT_SYM_DEF_t symmetric = { 0 };
> + TPMI_SH_AUTH_SESSION_t session = 0;
> + TPM2B_DIGEST_t policy_digest = { 0 };
> + grub_uint8_t i;
> + grub_err_t err;
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 25/33] tpm2_key_protector: Support authorized policy
2024-09-06 9:11 ` [PATCH v19 25/33] tpm2_key_protector: Support authorized policy Gary Lin via Grub-devel
@ 2024-10-16 16:08 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-16 16:08 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:17PM +0800, Gary Lin via Grub-devel wrote:
> This commit handles the TPM2_PolicyAuthorize command from the key file
> in TPM 2.0 Key File format.
>
> TPM2_PolicyAuthorize is the essential command to support authorized
> policy which allows the users to sign TPM policies with their own keys.
> Per TPM 2.0 Key File(*1), CommandPolicy for TPM2_PolicyAuthorize
> comprises 'TPM2B_PUBLIC pubkey', 'TPM2B_DIGEST policy_ref', and
> 'TPMT_SIGNATURE signature'. To verify the signature, the current policy
> digest is hashed with the hash algorithm written in 'signature', and then
> 'signature' is verified with the hashed policy digest and 'pubkey'. Once
> TPM accepts 'signature', TPM2_PolicyAuthorize is invoked to authorize the
> signed policy.
>
> To create the key file with authorized policy, here are the pcr-oracle(*2)
> commands:
>
> # Generate the RSA key and create the authorized policy file
> $ pcr-oracle \
> --rsa-generate-key \
> --private-key policy-key.pem \
> --auth authorized.policy \
> create-authorized-policy 0,2,4,7,9
>
> # Seal the secret with the authorized policy
> $ pcr-oracle \
> --key-format tpm2.0 \
> --auth authorized.policy \
> --input disk-secret.txt \
> --output sealed.key \
> seal-secret
>
> # Sign the predicted PCR policy
> $ pcr-oracle \
> --key-format tpm2.0 \
> --private-key policy-key.pem \
> --from eventlog \
> --stop-event "grub-file=grub.cfg" \
> --after \
> --input sealed.key \
> --output sealed.tpm \
> sign 0,2,4,7,9
>
> Then specify the key file and the key protector to grub.cfg in the EFI
> system partition:
>
> tpm2_key_protector_init -a RSA --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
> cryptomount -u <PART_UUID> -P tpm2
>
> For any change in the boot components, just run the 'sign' command again
> to update the signature in sealed.tpm, and TPM can unseal the key file
> with the updated PCR policy.
>
> (*1) https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
> (*2) https://github.com/okirch/pcr-oracle
>
> Signed-off-by: Gary Lin <glin@suse.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 26/33] tpm2_key_protector: Implement NV index
2024-09-06 9:11 ` [PATCH v19 26/33] tpm2_key_protector: Implement NV index Gary Lin via Grub-devel
@ 2024-10-16 16:11 ` Daniel Kiper
2024-10-17 2:54 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Daniel Kiper @ 2024-10-16 16:11 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:18PM +0800, Gary Lin via Grub-devel wrote:
> From: Patrick Colp <patrick.colp@oracle.com>
>
> Currently with the TPM2 protector, only SRK mode is supported and
> NV index support is just a stub. Implement the NV index option.
>
> Note: This only extends support on the unseal path. grub2_protect
s/grub2_protect/grub-protect/?
> has not been updated. tpm2-tools can be used to insert a key into
> the NV index.
>
> An example of inserting a key using tpm2-tools:
>
> # Get random key.
> tpm2_getrandom 32 > key.dat
>
> # Create primary object.
> tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx
>
> # Create policy object. `pcrs.dat` contains the PCR values to seal against.
> tpm2_startauthsession -S session.dat
> tpm2_policypcr -S session.dat -l sha256:7,11 -f pcrs.dat -L policy.dat
> tpm2_flushcontext session.dat
>
> # Seal key into TPM.
> cat key.dat | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-
> tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx
> tpm2_evictcontrol -C o -c sealing.ctx 0x81000000
>
> Then to unseal the key in grub, add this to grub.cfg:
>
> tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=7,11
> cryptomount -u <UUID> --protector tpm2
>
> Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Otherwise Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 27/33] cryptodisk: Fallback to passphrase
2024-09-06 9:11 ` [PATCH v19 27/33] cryptodisk: Fallback to passphrase Gary Lin via Grub-devel
@ 2024-10-16 16:14 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-16 16:14 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:19PM +0800, Gary Lin via Grub-devel wrote:
> From: Patrick Colp <patrick.colp@oracle.com>
>
> If a protector is specified, but it fails to unlock the disk, fall back
> to asking for the passphrase.
>
> Before requesting the passphrase, the error from the key protector(s)
> has to be cleared, or the later code (e.g., LUKS code) may stop as
> 'grub_errno' is set. This commit prints error from the key protector(s)
> and sets 'grub_errno' to 'GRUB_ERR_NONE' to have a fresh start.
>
> Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 29/33] diskfilter: look up cryptodisk devices first
2024-09-06 9:11 ` [PATCH v19 29/33] diskfilter: look up cryptodisk devices first Gary Lin via Grub-devel
@ 2024-10-16 16:19 ` Daniel Kiper
2024-10-17 2:56 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Daniel Kiper @ 2024-10-16 16:19 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko, Fabian Vogt
On Fri, Sep 06, 2024 at 05:11:21PM +0800, Gary Lin via Grub-devel wrote:
> When using disk auto-unlocking with TPM 2.0, the typical grub.cfg may
> look like this:
>
> tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
s/grub2/grub/
> cryptomount -u <PART-UUID> -P tpm2
> search --fs-uuid --set=root <FS-UUID>
>
> Since the disk search order is based on the order of module loading, the
> attacker could insert a malicious disk with the same FS-UUID root to
> trick grub2 to boot into the malicious root and further dump memory to
s/grub2/GRUB/ and below please...
> steal the unsealed key.
>
> Do defend against such an attack, we can specify the hint provided by
> 'grub-probe' to search the encrypted partition first:
>
> search --fs-uuid --set=root --hint='cryptouuid/<PART-UUID>' <FS-UUID>
>
> However, for LVM on an encrypted partition, the search hint provided by
> 'grub-probe' is:
>
> --hint='lvmid/<VG-UUID>/<LV-UUID>'
>
> It doesn't guarantee to look up the logical volume from the encrypted
> partition, so the attacker may have the chance to fool grub2 to boot
> into the malicious disk.
>
> To minimize the attack surface, this commit tweaks the disk device search
> in diskfilter to look up cryptodisk devices first and then others, so
> that the auto-unlocked disk will be found first, not the attacker's disk.
>
> Cc: Fabian Vogt <fvogt@suse.com>
> Signed-off-by: Gary Lin <glin@suse.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Otherwise Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 22/33] key_protector: Add TPM2 Key Protector
2024-10-16 15:44 ` Daniel Kiper
@ 2024-10-17 2:11 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-17 2:11 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Wed, Oct 16, 2024 at 05:44:29PM +0200, Daniel Kiper wrote:
> On Fri, Sep 06, 2024 at 05:11:14PM +0800, Gary Lin via Grub-devel wrote:
> > From: Hernan Gatta <hegatta@linux.microsoft.com>
> >
> > The TPM2 key protector is a module that enables the automatic retrieval
> > of a fully-encrypted disk's unlocking key from a TPM 2.0.
> >
> > The theory of operation is such that the module accepts various
> > arguments, most of which are optional and therefore possess reasonable
> > defaults. One of these arguments is the keyfile/tpm2key parameter, which
> > is mandatory. There are two supported key formats:
> >
> > 1. Raw Sealed Key (--keyfile)
> > When sealing a key with TPM2_Create, the public portion of the sealed
> > key is stored in TPM2B_PUBLIC, and the private portion is in
> > TPM2B_PRIVATE. The raw sealed key glues the fully marshalled
> > TPM2B_PUBLIC and TPM2B_PRIVATE into one file.
> >
> > 2. TPM 2.0 Key (--tpm2key)
> > The following is the ASN.1 definition of TPM 2.0 Key File:
> >
> > TPMPolicy ::= SEQUENCE {
> > CommandCode [0] EXPLICIT INTEGER
> > CommandPolicy [1] EXPLICIT OCTET STRING
> > }
> >
> > TPMAuthPolicy ::= SEQUENCE {
> > Name [0] EXPLICIT UTF8STRING OPTIONAL
> > Policy [1] EXPLICIT SEQUENCE OF TPMPolicy
> > }
> >
> > TPMKey ::= SEQUENCE {
> > type OBJECT IDENTIFIER
> > emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL
> > policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
> > secret [2] EXPLICIT OCTET STRING OPTIONAL
> > authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
> > description [4] EXPLICIT UTF8String OPTIONAL,
> > rsaParent [5] EXPLICIT BOOLEAN OPTIONAL,
> > parent INTEGER
> > pubkey OCTET STRING
> > privkey OCTET STRING
> > }
> >
> > The TPM2 key protector only expects a "sealed" key in DER encoding,
> > so 'type' is always 2.23.133.10.1.5, 'emptyAuth' is 'TRUE', and
> > 'secret' is empty. 'policy' and 'authPolicy' are the possible policy
> > command sequences to construst the policy digest to unseal the key.
> > Similar to the raw sealed key, the public portion (TPM2B_PUBLIC) of
> > the sealed key is stored in 'pubkey', and the private portion
> > (TPM2B_PRIVATE) is in 'privkey'.
> >
> > For more details: https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
> >
> > This sealed key file is created via the grub-protect tool. The tool
> > utilizes the TPM's sealing functionality to seal (i.e., encrypt) an
> > unlocking key using a Storage Root Key (SRK) to the values of various
> > Platform Configuration Registers (PCRs). These PCRs reflect the state
> > of the system as it boots. If the values are as expected, the system
> > may be considered trustworthy, at which point the TPM allows for a
> > caller to utilize the private component of the SRK to unseal (i.e.,
> > decrypt) the sealed key file. The caller, in this case, is this key
> > protector.
> >
> > The TPM2 key protector registers two commands:
> >
> > - tpm2_key_protector_init: Initializes the state of the TPM2 key
> > protector for later usage, clearing any
> > previous state, too, if any.
> >
> > - tpm2_key_protector_clear: Clears any state set by tpm2_key_protector_init.
> >
> > The way this is expected to be used requires the user to, either
> > interactively or, normally, via a boot script, initialize/configure
> > the key protector and then specify that it be used by the 'cryptomount'
> > command (modifications to this command are in a different patch).
> >
> > For instance, to unseal the raw sealed key file:
> >
> > tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-1.key
> > cryptomount -u <PART1_UUID> -P tpm2
> >
> > tpm2_key_protector_init --keyfile=(hd0,gpt1)/efi/grub2/sealed-2.key --pcrs=7,11
> > cryptomount -u <PART2_UUID> -P tpm2
> >
> > Or, to unseal the TPM 2.0 Key file:
> >
> > tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-1.tpm
> > cryptomount -u <PART1_UUID> -P tpm2
> >
> > tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-2.tpm --pcrs=7,11
> > cryptomount -u <PART2_UUID> -P tpm2
> >
> > If a user does not initialize the key protector and attempts to use it
> > anyway, the protector returns an error.
> >
> > Before unsealing the key, the TPM2 key protector follows the "TPMPolicy"
> > sequences to enforce the TPM policy commands to construct a valid policy
> > digest to unseal the key.
> >
> > For the TPM 2.0 Key files, 'authPolicy' may contain multiple "TPMPolicy"
> > sequences, the TPM2 key protector iterates 'authPolicy' to find a valid
> > sequence to unseal key. If 'authPolicy' is empty or all sequences in
> > 'authPolicy' fail, the protector tries the one from 'policy'. In case
> > 'policy' is also empty, the protector creates a "TPMPolicy" sequence
> > based on the given PCR selection.
> >
> > For the raw sealed key, the TPM2 key protector treats the key file as a
> > TPM 2.0 Key file without 'authPolicy' and 'policy', so the "TPMPolicy"
> > sequence is always based on the PCR selection from the command
> > parameters.
> >
> > This commit only supports one policy command: TPM2_PolicyPCR. The
> > command set will be extended to support advanced features, such as
> > authorized policy, in the later commits.
> >
> > Cc: Stefan Berger <stefanb@linux.ibm.com>
> > Cc: James Bottomley <jejb@linux.ibm.com>
> > Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> > grub-core/Makefile.core.def | 11 +
> > grub-core/commands/tpm2_key_protector/args.c | 129 ++
> > .../commands/tpm2_key_protector/module.c | 1153 +++++++++++++++++
> > grub-core/commands/tpm2_key_protector/tpm2.h | 36 +
> > .../commands/tpm2_key_protector/tpm2_args.h | 49 +
> > .../commands/tpm2_key_protector/tpm2key.asn | 49 +
> > .../commands/tpm2_key_protector/tpm2key.c | 499 +++++++
> > .../commands/tpm2_key_protector/tpm2key.h | 87 ++
> > .../tpm2_key_protector/tpm2key_asn1_tab.c | 63 +
> > 9 files changed, 2076 insertions(+)
> > create mode 100644 grub-core/commands/tpm2_key_protector/args.c
> > create mode 100644 grub-core/commands/tpm2_key_protector/module.c
> > create mode 100644 grub-core/commands/tpm2_key_protector/tpm2.h
> > create mode 100644 grub-core/commands/tpm2_key_protector/tpm2_args.h
> > create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.asn
> > create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.c
> > create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key.h
> > create mode 100644 grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c
> >
> > diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> > index 45b705a34..97ae4e49b 100644
> > --- a/grub-core/Makefile.core.def
> > +++ b/grub-core/Makefile.core.def
> > @@ -2578,6 +2578,17 @@ module = {
> > cppflags = '-I$(srcdir)/lib/tss2';
> > };
> >
> > +module = {
> > + name = tpm2_key_protector;
> > + common = commands/tpm2_key_protector/args.c;
> > + common = commands/tpm2_key_protector/module.c;
> > + common = commands/tpm2_key_protector/tpm2key.c;
> > + common = commands/tpm2_key_protector/tpm2key_asn1_tab.c;
> > + /* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */
> > + enable = efi;
> > + cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub';
> > +};
> > +
> > module = {
> > name = tr;
> > common = commands/tr.c;
> > diff --git a/grub-core/commands/tpm2_key_protector/args.c b/grub-core/commands/tpm2_key_protector/args.c
> > new file mode 100644
> > index 000000000..c58cbe307
> > --- /dev/null
> > +++ b/grub-core/commands/tpm2_key_protector/args.c
> > @@ -0,0 +1,129 @@
> > +/*
> > + * GRUB -- GRand Unified Bootloader
> > + * Copyright (C) 2022 Microsoft Corporation
> > + * Copyright (C) 2024 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 "tpm2_args.h"
> > +
> > +grub_err_t
> > +grub_tpm2_protector_parse_pcrs (char *value, grub_uint8_t *pcrs,
> > + grub_uint8_t *pcr_count)
> > +{
> > + char *current_pcr = value;
> > + char *next_pcr;
> > + const char *pcr_end;
> > + grub_uint64_t pcr;
> > + grub_uint8_t i;
> > +
> > + if (grub_strlen (value) == 0)
> > + return GRUB_ERR_BAD_ARGUMENT;
> > +
> > + *pcr_count = 0;
> > + for (i = 0; i < TPM_MAX_PCRS; i++)
> > + {
> > + next_pcr = grub_strchr (current_pcr, ',');
> > + if (next_pcr == current_pcr)
> > + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Empty entry in PCR list");
> > + if (next_pcr != NULL)
> > + *next_pcr = '\0';
> > +
> > + grub_errno = GRUB_ERR_NONE;
>
> This is probably remnant from previous version of the patch.
>
Ah, yeah. There is no need to reset grub_errno here.
> > + pcr = grub_strtoul (current_pcr, &pcr_end, 10);
> > + if (*current_pcr == '\0' || *pcr_end != '\0')
> > + return grub_error (GRUB_ERR_BAD_NUMBER, "Entry '%s' in PCR list is not a number", current_pcr);
> > +
> > + if (pcr > TPM_MAX_PCRS)
> > + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Entry %" PRIuGRUB_UINT64_T " in PCR list is too large to be a PCR number, PCR numbers range from 0 to %u", pcr, TPM_MAX_PCRS);
> > +
> > + pcrs[i] = (grub_uint8_t) pcr;
> > + ++(*pcr_count);
> > +
> > + if (next_pcr == NULL)
> > + break;
> > +
> > + current_pcr = next_pcr + 1;
> > + if (*current_pcr == '\0')
> > + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Trailing comma at the end of PCR list");
> > + }
> > +
> > + if (i == TPM_MAX_PCRS)
> > + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Too many PCRs in PCR list, the maximum number of PCRs is %u", TPM_MAX_PCRS);
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +grub_err_t
> > +grub_tpm2_protector_parse_asymmetric (const char *value,
> > + grub_srk_type_t *srk_type)
> > +{
> > + if (grub_strcasecmp (value, "ECC") == 0 ||
> > + grub_strcasecmp (value, "ECC_NIST_P256") == 0)
> > + {
> > + srk_type->type = TPM_ALG_ECC;
> > + srk_type->detail.ecc_curve = TPM_ECC_NIST_P256;
> > + }
> > + else if (grub_strcasecmp (value, "RSA") == 0 ||
> > + grub_strcasecmp (value, "RSA2048") == 0)
> > + {
> > + srk_type->type = TPM_ALG_RSA;
> > + srk_type->detail.rsa_bits = 2048;
> > + }
> > + else
> > + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid asymmetric key type", value);
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +grub_err_t
> > +grub_tpm2_protector_parse_bank (const char *value, TPM_ALG_ID_t *bank)
> > +{
> > + if (grub_strcasecmp (value, "SHA1") == 0)
> > + *bank = TPM_ALG_SHA1;
> > + else if (grub_strcasecmp (value, "SHA256") == 0)
> > + *bank = TPM_ALG_SHA256;
> > + else if (grub_strcasecmp (value, "SHA384") == 0)
> > + *bank = TPM_ALG_SHA384;
> > + else if (grub_strcasecmp (value, "SHA512") == 0)
> > + *bank = TPM_ALG_SHA512;
> > + else
> > + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value '%s' is not a valid PCR bank", value);
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +grub_err_t
> > +grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE_t *handle)
> > +{
> > + grub_uint64_t num;
> > + const char *str_end;
> > +
> > + grub_errno = GRUB_ERR_NONE;
>
> Ditto. Please fix similar problems everywhere...
>
Okay. Will remove the unnecessary grub_errno in the next version.
> > + num = grub_strtoul (value, &str_end, 0);
> > + if (*value == '\0' || *str_end != '\0')
> > + return grub_error (GRUB_ERR_BAD_NUMBER, "TPM handle value '%s' is not a number", value);
> > +
> > + if (num > GRUB_UINT_MAX)
> > + return grub_error (GRUB_ERR_OUT_OF_RANGE, "Value %lu is too large to be a TPM handle, TPM handles are unsigned 32-bit integers", num);
> > +
> > + *handle = (TPM_HANDLE_t) num;
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
> > new file mode 100644
> > index 000000000..909c3cc6a
> > --- /dev/null
> > +++ b/grub-core/commands/tpm2_key_protector/module.c
> > @@ -0,0 +1,1153 @@
> > +/*
> > + * GRUB -- GRand Unified Bootloader
> > + * Copyright (C) 2022 Microsoft Corporation
> > + * Copyright (C) 2024 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/extcmd.h>
> > +#include <grub/file.h>
> > +#include <grub/list.h>
> > +#include <grub/misc.h>
> > +#include <grub/mm.h>
> > +#include <grub/key_protector.h>
> > +
> > +#include <tss2_buffer.h>
> > +#include <tss2_types.h>
> > +#include <tss2_mu.h>
> > +
> > +#include "tpm2_args.h"
> > +#include "tpm2.h"
> > +#include "tpm2key.h"
> > +
> > +GRUB_MOD_LICENSE ("GPLv3+");
> > +
> > +typedef enum grub_tpm2_protector_mode
> > +{
> > + GRUB_TPM2_PROTECTOR_MODE_UNSET,
> > + GRUB_TPM2_PROTECTOR_MODE_SRK,
> > + GRUB_TPM2_PROTECTOR_MODE_NV
> > +} grub_tpm2_protector_mode_t;
> > +
> > +enum grub_tpm2_protector_options
> > +{
> > + OPTION_MODE,
> > + OPTION_PCRS,
> > + OPTION_BANK,
> > + OPTION_TPM2KEY,
> > + OPTION_KEYFILE,
> > + OPTION_SRK,
> > + OPTION_ASYMMETRIC,
> > + OPTION_NVINDEX
> > +};
>
> May I ask you to be more consistent and define enums
> as types like you did for grub_tpm2_protector_mode?
>
Okay.
> And again, you can drop "grub_" prefixes from all stuff which is
> internal for a given C file.
>
Will fix them in the next version.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 24/33] util/grub-protect: Add new tool
2024-10-16 16:04 ` Daniel Kiper
@ 2024-10-17 2:39 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-17 2:39 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Wed, Oct 16, 2024 at 06:04:43PM +0200, Daniel Kiper wrote:
> On Fri, Sep 06, 2024 at 05:11:16PM +0800, Gary Lin via Grub-devel wrote:
> > From: Hernan Gatta <hegatta@linux.microsoft.com>
> >
> > To utilize the key protectors framework, there must be a way to protect
> > full-disk encryption keys in the first place. The grub-protect tool
> > includes support for the TPM2 key protector but other protectors that
> > require setup ahead of time can be supported in the future.
> >
> > For the TPM2 key protector, the intended flow is for a user to have a
> > LUKS 1 or LUKS 2-protected fully-encrypted disk. The user then creates a
> > new LUKS key file, say by reading /dev/urandom into a file, and creates
> > a new LUKS key slot for this key. Then, the user invokes the grub-protect
> > tool to seal this key file to a set of PCRs using the system's TPM 2.0.
> > The resulting sealed key file is stored in an unencrypted partition such
> > as the EFI System Partition (ESP) so that GRUB may read it. The user also
> > has to ensure the cryptomount command is included in GRUB's boot script
> > and that it carries the requisite key protector (-P) parameter.
> >
> > Sample usage:
> >
> > $ dd if=/dev/urandom of=luks-key bs=1 count=32
> > $ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2 --hash=sha512
> >
> > To seal the key with TPM 2.0 Key File (recommended):
> >
> > $ sudo grub-protect --action=add \
> > --protector=tpm2 \
> > --tpm2-pcrs=0,2,4,7,9 \
>
> Please replace tabs with spaces here...
>
Will fix it in the next version.
> > --tpm2key \
> > --tpm2-keyfile=luks-key \
> > --tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm
> >
> > Or, to seal the key with the raw sealed key:
> >
> > $ sudo grub-protect --action=add \
> > --protector=tpm2 \
> > --tpm2-pcrs=0,2,4,7,9 \
>
> Ditto...
>
> > --tpm2-keyfile=luks-key \
> > --tpm2-outfile=/boot/efi/boot/grub2/sealed.key
> >
> > Then, in the boot script, for TPM 2.0 Key File:
> >
> > tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
> > cryptomount -u <SDB1_UUID> -P tpm2
> >
> > Or, for the raw sealed key:
> >
> > tpm2_key_protector_init --keyfile=(hd0,gpt1)/boot/grub2/sealed.key --pcrs=0,2,4,7,9
> > cryptomount -u <SDB1_UUID> -P tpm2
> >
> > The benefit of using TPM 2.0 Key File is that the PCR set is already
> > written in the key file, so there is no need to specify PCRs when
> > invoking tpm2_key_protector_init.
> >
> > Cc: Stefan Berger <stefanb@linux.ibm.com>
> > Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
> > ---
> > .gitignore | 2 +
> > Makefile.util.def | 26 +
> > configure.ac | 30 +
> > docs/man/grub-protect.h2m | 4 +
> > util/grub-protect.c | 1394 +++++++++++++++++++++++++++++++++++++
> > 5 files changed, 1456 insertions(+)
> > create mode 100644 docs/man/grub-protect.h2m
> > create mode 100644 util/grub-protect.c
> >
> > diff --git a/.gitignore b/.gitignore
> > index 4c1f91db8..2105d87c8 100644
> > --- a/.gitignore
> > +++ b/.gitignore
> > @@ -169,6 +169,8 @@ widthspec.bin
> > /grub-ofpathname.exe
> > /grub-probe
> > /grub-probe.exe
> > +/grub-protect
> > +/grub-protect.exe
> > /grub-reboot
> > /grub-render-label
> > /grub-render-label.exe
> > diff --git a/Makefile.util.def b/Makefile.util.def
> > index fb82f59a0..074c0aff7 100644
> > --- a/Makefile.util.def
> > +++ b/Makefile.util.def
> > @@ -208,6 +208,32 @@ program = {
> > ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
> > };
> >
> > +program = {
> > + name = grub-protect;
> > + mansection = 1;
> > +
> > + common = grub-core/kern/emu/argp_common.c;
> > + common = grub-core/osdep/init.c;
> > + common = grub-core/lib/tss2/buffer.c;
> > + common = grub-core/lib/tss2/tss2_mu.c;
> > + common = grub-core/lib/tss2/tpm2_cmd.c;
> > + common = grub-core/commands/tpm2_key_protector/args.c;
> > + common = grub-core/commands/tpm2_key_protector/tpm2key_asn1_tab.c;
> > + common = util/grub-protect.c;
> > + common = util/probe.c;
> > +
> > + 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 = grub-core/lib/gnulib/libgnu.a;
> > + ldadd = '$(LIBTASN1)';
> > + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
> > +
> > + condition = COND_GRUB_PROTECT;
> > +};
> > +
> > program = {
> > name = grub-mkrelpath;
> > mansection = 1;
> > diff --git a/configure.ac b/configure.ac
> > index 458b8382b..ad1e7bea5 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -76,6 +76,7 @@ grub_TRANSFORM([grub-mkpasswd-pbkdf2])
> > grub_TRANSFORM([grub-mkrelpath])
> > grub_TRANSFORM([grub-mkrescue])
> > grub_TRANSFORM([grub-probe])
> > +grub_TRANSFORM([grub-protect])
> > grub_TRANSFORM([grub-reboot])
> > grub_TRANSFORM([grub-script-check])
> > grub_TRANSFORM([grub-set-default])
> > @@ -2068,6 +2069,29 @@ fi
> > AC_SUBST([LIBZFS])
> > AC_SUBST([LIBNVPAIR])
> >
> > +AC_ARG_ENABLE([grub-protect],
> > + [AS_HELP_STRING([--enable-grub-protect],
> > + [build and install the `grub-protect' utility (default=guessed)])])
> > +if test x"$enable_grub_protect" = xno ; then
> > + grub_protect_excuse="explicitly disabled"
> > +fi
> > +
> > +LIBTASN1=
> > +if test x"$grub_protect_excuse" = x ; then
> > + AC_CHECK_LIB([tasn1], [asn1_write_value], [LIBTASN1="-ltasn1"], [grub_protect_excuse="need libtasn1 library"])
> > +fi
> > +AC_SUBST([LIBTASN1])
> > +
> > +if test x"$enable_grub_protect" = xyes && test x"$grub_protect_excuse" != x ; then
> > + AC_MSG_ERROR([grub-protect was explicitly requested but can't be compiled ($grub_protect_excuse)])
> > +fi
> > +if test x"$grub_protect_excuse" = x ; then
> > +enable_grub_protect=yes
> > +else
> > +enable_grub_protect=no
> > +fi
> > +AC_SUBST([enable_grub_protect])
> > +
> > LIBS=""
> >
> > AC_SUBST([FONT_SOURCE])
> > @@ -2184,6 +2208,7 @@ AM_CONDITIONAL([COND_GRUB_EMU_SDL], [test x$enable_grub_emu_sdl = xyes])
> > AM_CONDITIONAL([COND_GRUB_EMU_PCI], [test x$enable_grub_emu_pci = xyes])
> > AM_CONDITIONAL([COND_GRUB_MKFONT], [test x$enable_grub_mkfont = xyes])
> > AM_CONDITIONAL([COND_GRUB_MOUNT], [test x$enable_grub_mount = xyes])
> > +AM_CONDITIONAL([COND_GRUB_PROTECT], [test x$enable_grub_protect = xyes])
> > AM_CONDITIONAL([COND_HAVE_FONT_SOURCE], [test x$FONT_SOURCE != x])
> > if test x$FONT_SOURCE != x ; then
> > HAVE_FONT_SOURCE=1
> > @@ -2311,6 +2336,11 @@ echo grub-mount: Yes
> > else
> > echo grub-mount: No "($grub_mount_excuse)"
> > fi
> > +if [ x"$grub_protect_excuse" = x ]; then
> > +echo grub-protect: Yes
> > +else
> > +echo grub-protect: No "($grub_protect_excuse)"
> > +fi
> > if [ x"$starfield_excuse" = x ]; then
> > echo starfield theme: Yes
> > echo With DejaVuSans font from $DJVU_FONT_SOURCE
> > diff --git a/docs/man/grub-protect.h2m b/docs/man/grub-protect.h2m
> > new file mode 100644
> > index 000000000..ecf1c9eab
> > --- /dev/null
> > +++ b/docs/man/grub-protect.h2m
> > @@ -0,0 +1,4 @@
> > +[NAME]
> > +grub-protect \- protect a disk key with a key protector
> > +[DESCRIPTION]
> > +grub-protect helps to protect a disk encryption key with a specified key protector.
> > diff --git a/util/grub-protect.c b/util/grub-protect.c
> > new file mode 100644
> > index 000000000..fb4ea4079
> > --- /dev/null
> > +++ b/util/grub-protect.c
> > @@ -0,0 +1,1394 @@
> > +/*
> > + * GRUB -- GRand Unified Bootloader
> > + * Copyright (C) 2022 Microsoft Corporation
> > + * Copyright (C) 2023 SUSE LLC
> > + * Copyright (C) 2024 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 <config.h>
> > +
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <libtasn1.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +
> > +#include <grub/emu/hostdisk.h>
> > +#include <grub/emu/misc.h>
> > +
> > +#include <grub/util/misc.h>
> > +
> > +#include <tss2_buffer.h>
> > +#include <tss2_mu.h>
> > +#include <tcg2.h>
> > +#include <tpm2_args.h>
> > +#include <tpm2.h>
> > +
> > +#pragma GCC diagnostic ignored "-Wmissing-prototypes"
> > +#pragma GCC diagnostic ignored "-Wmissing-declarations"
> > +#include <argp.h>
> > +#pragma GCC diagnostic error "-Wmissing-prototypes"
> > +#pragma GCC diagnostic error "-Wmissing-declarations"
> > +
> > +#include "progname.h"
> > +
> > +/* Unprintable option keys for argp */
> > +typedef enum grub_protect_opt
> > +{
> > + /* General */
> > + GRUB_PROTECT_OPT_ACTION = 'a',
> > + GRUB_PROTECT_OPT_PROTECTOR = 'p',
> > + /* TPM2 */
> > + GRUB_PROTECT_OPT_TPM2_DEVICE = 0x100,
> > + GRUB_PROTECT_OPT_TPM2_PCRS,
> > + GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
> > + GRUB_PROTECT_OPT_TPM2_BANK,
> > + GRUB_PROTECT_OPT_TPM2_SRK,
> > + GRUB_PROTECT_OPT_TPM2_KEYFILE,
> > + GRUB_PROTECT_OPT_TPM2_OUTFILE,
> > + GRUB_PROTECT_OPT_TPM2_EVICT,
> > + GRUB_PROTECT_OPT_TPM2_TPM2KEY
> > +} grub_protect_opt;
>
> Again, you can drop "grub_" prefixes for internal stuff...
>
I was thinking about matching the name 'grub-protect' with the types and
functions here. Using 'protect_' or 'PROTECT_' is enough anyway.
> > +/* Option flags to keep track of specified arguments */
> > +typedef enum grub_protect_arg
> > +{
> > + /* General */
> > + GRUB_PROTECT_ARG_ACTION = 1 << 0,
> > + GRUB_PROTECT_ARG_PROTECTOR = 1 << 1,
> > + /* TPM2 */
> > + GRUB_PROTECT_ARG_TPM2_DEVICE = 1 << 2,
> > + GRUB_PROTECT_ARG_TPM2_PCRS = 1 << 3,
> > + GRUB_PROTECT_ARG_TPM2_ASYMMETRIC = 1 << 4,
> > + GRUB_PROTECT_ARG_TPM2_BANK = 1 << 5,
> > + GRUB_PROTECT_ARG_TPM2_SRK = 1 << 6,
> > + GRUB_PROTECT_ARG_TPM2_KEYFILE = 1 << 7,
> > + GRUB_PROTECT_ARG_TPM2_OUTFILE = 1 << 8,
> > + GRUB_PROTECT_ARG_TPM2_EVICT = 1 << 9,
> > + GRUB_PROTECT_ARG_TPM2_TPM2KEY = 1 << 10
> > +} grub_protect_arg_t;
>
> Ditto and in other patches too...
>
> > +typedef enum grub_protect_protector
> > +{
> > + GRUB_PROTECT_TYPE_ERROR,
> > + GRUB_PROTECT_TYPE_TPM2
> > +} grub_protect_protector_t;
> > +
> > +typedef enum grub_protect_action
> > +{
> > + GRUB_PROTECT_ACTION_ERROR,
> > + GRUB_PROTECT_ACTION_ADD,
> > + GRUB_PROTECT_ACTION_REMOVE
> > +} grub_protect_action_t;
> > +
> > +struct grub_protect_args
> > +{
> > + grub_protect_arg_t args;
> > + grub_protect_action_t action;
> > + grub_protect_protector_t protector;
> > +
> > + const char *tpm2_device;
> > + grub_uint8_t tpm2_pcrs[TPM_MAX_PCRS];
> > + grub_uint8_t tpm2_pcr_count;
> > + grub_srk_type_t srk_type;
> > + TPM_ALG_ID_t tpm2_bank;
> > + TPM_HANDLE_t tpm2_srk;
> > + const char *tpm2_keyfile;
> > + const char *tpm2_outfile;
> > + int tpm2_evict;
> > + int tpm2_tpm2key;
> > +};
> > +
> > +static struct argp_option grub_protect_options[] =
> > + {
> > + /* Top-level options */
> > + {
> > + .name = "action",
> > + .key = 'a',
> > + .arg = "add|remove",
> > + .flags = 0,
> > + .doc =
> > + N_("Add or remove a key protector to or from a key."),
> > + .group = 0
> > + },
> > + {
> > + .name = "protector",
> > + .key = 'p',
> > + .arg = "tpm2",
> > + .flags = 0,
> > + .doc =
> > + N_("Set key protector to use (only tpm2 is currently supported)."),
> > + .group = 0
> > + },
> > + /* TPM2 key protector options */
> > + {
> > + .name = "tpm2-device",
> > + .key = GRUB_PROTECT_OPT_TPM2_DEVICE,
> > + .arg = "FILE",
> > + .flags = 0,
> > + .doc =
> > + N_("Set the path to the TPM2 device. (default: /dev/tpm0)"),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2-pcrs",
> > + .key = GRUB_PROTECT_OPT_TPM2_PCRS,
> > + .arg = "0[,1]...",
> > + .flags = 0,
> > + .doc =
> > + N_("Set a comma-separated list of PCRs used to authorize key release "
> > + "e.g., '7,11'. Please be aware that PCR 0~7 are used by the "
> > + "firmware and the measurement result may change after a "
> > + "firmware update (for baremetal systems) or a package "
> > + "(OVMF/SeaBIOS/SLOF) update in the VM host. This may lead to "
> > + "the failure of key unsealing. (default: 7)"),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2-bank",
> > + .key = GRUB_PROTECT_OPT_TPM2_BANK,
> > + .arg = "ALG",
> > + .flags = 0,
> > + .doc =
> > + N_("Set the bank of PCRs used to authorize key release: "
> > + "SHA1, SHA256, SHA384, or SHA512. (default: SHA256)"),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2-keyfile",
> > + .key = GRUB_PROTECT_OPT_TPM2_KEYFILE,
> > + .arg = "FILE",
> > + .flags = 0,
> > + .doc =
> > + N_("Set the path to a file that contains the cleartext key to protect."),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2-outfile",
> > + .key = GRUB_PROTECT_OPT_TPM2_OUTFILE,
> > + .arg = "FILE",
> > + .flags = 0,
> > + .doc =
> > + N_("Set the path to the file that will contain the key after sealing "
> > + "(must be accessible to GRUB during boot)."),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2-srk",
> > + .key = GRUB_PROTECT_OPT_TPM2_SRK,
> > + .arg = "NUM",
> > + .flags = 0,
> > + .doc =
> > + N_("Set the SRK handle if the SRK is to be made persistent."),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2-asymmetric",
> > + .key = GRUB_PROTECT_OPT_TPM2_ASYMMETRIC,
> > + .arg = "TYPE",
> > + .flags = 0,
> > + .doc =
> > + N_("Set the type of SRK: RSA (RSA2048) and ECC (ECC_NIST_P256)."
> > + "(default: ECC)"),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2-evict",
> > + .key = GRUB_PROTECT_OPT_TPM2_EVICT,
> > + .arg = NULL,
> > + .flags = 0,
> > + .doc =
> > + N_("Evict a previously persisted SRK from the TPM, if any."),
> > + .group = 0
> > + },
> > + {
> > + .name = "tpm2key",
> > + .key = GRUB_PROTECT_OPT_TPM2_TPM2KEY,
> > + .arg = NULL,
> > + .flags = 0,
> > + .doc =
> > + N_("Use TPM 2.0 Key File format instead of the raw format."),
> > + .group = 0
> > + },
> > + /* End of list */
> > + { 0, 0, 0, 0, 0, 0 }
> > + };
> > +
> > +static int protector_tpm2_fd = -1;
> > +
> > +static grub_err_t
> > +protect_read_file (const char *filepath, void **buffer, size_t *buffer_size)
> > +{
> > + grub_err_t err;
> > + FILE *f;
> > + long len;
> > + void *buf;
> > +
> > + f = fopen (filepath, "rb");
> > + if (f == NULL)
> > + return GRUB_ERR_FILE_NOT_FOUND;
> > +
> > + if (fseek (f, 0, SEEK_END))
> > + {
> > + err = GRUB_ERR_FILE_READ_ERROR;
> > + goto exit1;
> > + }
> > +
> > + len = ftell (f);
> > + if (len <= 0)
> > + {
> > + err = GRUB_ERR_FILE_READ_ERROR;
> > + goto exit1;
> > + }
> > +
> > + rewind (f);
> > +
> > + buf = grub_malloc (len);
> > + if (buf == NULL)
> > + {
> > + err = GRUB_ERR_OUT_OF_MEMORY;
> > + goto exit1;
> > + }
> > +
> > + if (fread (buf, len, 1, f) != 1)
> > + {
> > + err = GRUB_ERR_FILE_READ_ERROR;
> > + goto exit2;
> > + }
> > +
> > + *buffer = buf;
> > + *buffer_size = len;
> > +
> > + buf = NULL;
> > + err = GRUB_ERR_NONE;
> > +
> > + exit2:
> > + grub_free (buf);
> > +
> > + exit1:
> > + fclose (f);
> > +
> > + return err;
> > +}
> > +
> > +static grub_err_t
> > +protect_write_file (const char *filepath, void *buffer, size_t buffer_size)
> > +{
> > + grub_err_t err;
> > + FILE *f;
> > +
> > + f = fopen (filepath, "wb");
> > + if (f == NULL)
> > + return GRUB_ERR_FILE_NOT_FOUND;
> > +
> > + if (fwrite (buffer, buffer_size, 1, f) != 1)
> > + {
> > + err = GRUB_ERR_WRITE_ERROR;
> > + goto exit1;
>
> s/exit1/exit/
>
Will fix it in the next version.
> > + }
> > +
> > + err = GRUB_ERR_NONE;
> > +
> > + exit1:
> > + fclose (f);
> > +
> > + return err;
> > +}
> > +
> > +grub_err_t
> > +grub_tcg2_get_max_output_size (grub_size_t *size)
>
> This function seems unused.
This is the tcg2 function defined in grub-core/lib/tss2/tcg2.h.
>
> > +{
> > + if (size == NULL)
> > + return GRUB_ERR_BAD_ARGUMENT;
> > +
> > + *size = GRUB_TPM2_BUFFER_CAPACITY;
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +grub_err_t
> > +grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
> > + grub_size_t output_size, grub_uint8_t *output)
>
> Ditto...
>
This is another tcg2 function.
The tcg2 functions are architecture dependent. Since grub-protect is for
the user space, grub_tcg2_submit_command() here is designed to send the
TPM2 commands through /dev/tpm0 or other path specified by '--tpm2-device'.
> > +{
> > + static const grub_size_t header_size = sizeof (grub_uint16_t) +
> > + (2 * sizeof(grub_uint32_t));
> > +
> > + if (write (protector_tpm2_fd, input, input_size) != input_size)
> > + return GRUB_ERR_BAD_DEVICE;
> > +
> > + if (read (protector_tpm2_fd, output, output_size) < header_size)
> > + return GRUB_ERR_BAD_DEVICE;
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +static grub_err_t
> > +protect_tpm2_open_device (const char *dev_node)
> > +{
> > + if (protector_tpm2_fd != -1)
> > + return GRUB_ERR_NONE;
> > +
> > + protector_tpm2_fd = open (dev_node, O_RDWR);
> > + if (protector_tpm2_fd == -1)
> > + {
> > + fprintf (stderr, "Could not open TPM device (%s).\n", strerror (errno));
> > + return GRUB_ERR_FILE_NOT_FOUND;
> > + }
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +static grub_err_t
> > +protect_tpm2_close_device (void)
> > +{
> > + int err;
> > +
> > + if (protector_tpm2_fd == -1)
> > + return GRUB_ERR_NONE;
> > +
> > + err = close (protector_tpm2_fd);
> > + if (err != GRUB_ERR_NONE)
> > + {
> > + fprintf (stderr, "Could not close TPM device (Error: %u).\n", errno);
> > + return GRUB_ERR_IO;
> > + }
> > +
> > + protector_tpm2_fd = -1;
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +static grub_err_t
> > +protect_tpm2_get_policy_digest (struct grub_protect_args *args, TPM2B_DIGEST_t *digest)
> > +{
> > + TPM_RC_t rc;
> > + TPML_PCR_SELECTION_t pcr_sel = {
> > + .count = 1,
> > + .pcrSelections = {
> > + {
> > + .hash = args->tpm2_bank,
> > + .sizeOfSelect = 3,
> > + .pcrSelect = { 0 }
> > + },
> > + }
> > + };
> > + TPML_PCR_SELECTION_t pcr_sel_out = { 0 };
>
> Redundant spaces around 0.
>
> > + TPML_DIGEST_t pcr_values = { 0 };
>
> Ditto and below...
>
Will fix them in the next version.
Gary Lin
> > + TPM2B_DIGEST_t pcr_digest = { 0 };
> > + grub_size_t pcr_digest_len;
> > + TPM2B_MAX_BUFFER_t pcr_concat = { 0 };
> > + grub_size_t pcr_concat_len;
> > + grub_uint8_t *pcr_cursor;
> > + TPM2B_NONCE_t nonce = { 0 };
> > + TPM2B_ENCRYPTED_SECRET_t salt = { 0 };
> > + TPMT_SYM_DEF_t symmetric = { 0 };
> > + TPMI_SH_AUTH_SESSION_t session = 0;
> > + TPM2B_DIGEST_t policy_digest = { 0 };
> > + grub_uint8_t i;
> > + grub_err_t err;
>
> Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 26/33] tpm2_key_protector: Implement NV index
2024-10-16 16:11 ` Daniel Kiper
@ 2024-10-17 2:54 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-17 2:54 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Wed, Oct 16, 2024 at 06:11:49PM +0200, Daniel Kiper wrote:
> On Fri, Sep 06, 2024 at 05:11:18PM +0800, Gary Lin via Grub-devel wrote:
> > From: Patrick Colp <patrick.colp@oracle.com>
> >
> > Currently with the TPM2 protector, only SRK mode is supported and
> > NV index support is just a stub. Implement the NV index option.
> >
> > Note: This only extends support on the unseal path. grub2_protect
>
> s/grub2_protect/grub-protect/?
>
Yes, it's grub-protect. Will fix it in the next version.
Gary Lin
> > has not been updated. tpm2-tools can be used to insert a key into
> > the NV index.
> >
> > An example of inserting a key using tpm2-tools:
> >
> > # Get random key.
> > tpm2_getrandom 32 > key.dat
> >
> > # Create primary object.
> > tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx
> >
> > # Create policy object. `pcrs.dat` contains the PCR values to seal against.
> > tpm2_startauthsession -S session.dat
> > tpm2_policypcr -S session.dat -l sha256:7,11 -f pcrs.dat -L policy.dat
> > tpm2_flushcontext session.dat
> >
> > # Seal key into TPM.
> > cat key.dat | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-
> > tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx
> > tpm2_evictcontrol -C o -c sealing.ctx 0x81000000
> >
> > Then to unseal the key in grub, add this to grub.cfg:
> >
> > tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=7,11
> > cryptomount -u <UUID> --protector tpm2
> >
> > Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
> > Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>
> Otherwise Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
>
> Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 29/33] diskfilter: look up cryptodisk devices first
2024-10-16 16:19 ` Daniel Kiper
@ 2024-10-17 2:56 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-17 2:56 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko, Fabian Vogt
On Wed, Oct 16, 2024 at 06:19:33PM +0200, Daniel Kiper wrote:
> On Fri, Sep 06, 2024 at 05:11:21PM +0800, Gary Lin via Grub-devel wrote:
> > When using disk auto-unlocking with TPM 2.0, the typical grub.cfg may
> > look like this:
> >
> > tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
>
> s/grub2/grub/
>
> > cryptomount -u <PART-UUID> -P tpm2
> > search --fs-uuid --set=root <FS-UUID>
> >
> > Since the disk search order is based on the order of module loading, the
> > attacker could insert a malicious disk with the same FS-UUID root to
> > trick grub2 to boot into the malicious root and further dump memory to
>
> s/grub2/GRUB/ and below please...
Will fix them in the next version.
Gary Lin
>
> > steal the unsealed key.
> >
> > Do defend against such an attack, we can specify the hint provided by
> > 'grub-probe' to search the encrypted partition first:
> >
> > search --fs-uuid --set=root --hint='cryptouuid/<PART-UUID>' <FS-UUID>
> >
> > However, for LVM on an encrypted partition, the search hint provided by
> > 'grub-probe' is:
> >
> > --hint='lvmid/<VG-UUID>/<LV-UUID>'
> >
> > It doesn't guarantee to look up the logical volume from the encrypted
> > partition, so the attacker may have the chance to fool grub2 to boot
> > into the malicious disk.
> >
> > To minimize the attack surface, this commit tweaks the disk device search
> > in diskfilter to look up cryptodisk devices first and then others, so
> > that the auto-unlocked disk will be found first, not the attacker's disk.
> >
> > Cc: Fabian Vogt <fvogt@suse.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
> > Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>
> Otherwise Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
>
> Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 30/33] tpm2_key_protector: Add grub-emu support
2024-09-06 9:11 ` [PATCH v19 30/33] tpm2_key_protector: Add grub-emu support Gary Lin via Grub-devel
@ 2024-10-17 17:57 ` Daniel Kiper
2024-10-18 9:31 ` Gary Lin via Grub-devel
0 siblings, 1 reply; 82+ messages in thread
From: Daniel Kiper @ 2024-10-17 17:57 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:22PM +0800, Gary Lin via Grub-devel wrote:
> As a preparation to test tpm2_key_protector with grub-emu, the new
> option, --tpm-device, is introduced to specify the TPM device for
> grub-emu so that grub-emu can share the emulated TPM device with
> the host.
s/can share the emulated TPM device with/can access an emulated TPM device from/?
> Since grub-emu can directly access the device node on host, it's easy to
s/device node/device/
> implement the essential TCG2 command submission function with the
> read/write functions and enable tpm2_key_protector module for grub-emu,
> so that we can further test TPM2 key unsealing with grub-emu.
>
> Signed-off-by: Gary Lin <glin@suse.com>
> Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Otherwise Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
... and three nits below...
> ---
> grub-core/Makefile.core.def | 3 ++
> grub-core/kern/emu/main.c | 11 ++++++-
> grub-core/kern/emu/misc.c | 51 +++++++++++++++++++++++++++++++++
> grub-core/lib/tss2/tcg2_emu.c | 54 +++++++++++++++++++++++++++++++++++
> include/grub/emu/misc.h | 5 ++++
> 5 files changed, 123 insertions(+), 1 deletion(-)
> create mode 100644 grub-core/lib/tss2/tcg2_emu.c
>
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 97ae4e49b..40427165e 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -2574,7 +2574,9 @@ module = {
> common = lib/tss2/tpm2_cmd.c;
> common = lib/tss2/tss2.c;
> efi = lib/efi/tcg2.c;
> + emu = lib/tss2/tcg2_emu.c;
> enable = efi;
> + enable = emu;
> cppflags = '-I$(srcdir)/lib/tss2';
> };
>
> @@ -2586,6 +2588,7 @@ module = {
> common = commands/tpm2_key_protector/tpm2key_asn1_tab.c;
> /* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */
> enable = efi;
> + enable = emu;
> cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub';
> };
>
> diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
> index 855b11c3d..c10838613 100644
> --- a/grub-core/kern/emu/main.c
> +++ b/grub-core/kern/emu/main.c
> @@ -55,7 +55,7 @@
> static jmp_buf main_env;
>
> /* Store the prefix specified by an argument. */
> -static char *root_dev = NULL, *dir = NULL;
> +static char *root_dev = NULL, *dir = NULL, *tpm_dev = NULL;
>
> grub_addr_t grub_modbase = 0;
>
> @@ -108,6 +108,7 @@ static struct argp_option options[] = {
> {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
> {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
> {"kexec", 'X', 0, 0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0},
> + {"tpm-device", 't', N_("DEV"), 0, N_("Set TPM device."), 0},
s/Set/set/? It looks all messages start with lowercase...
> { 0, 0, 0, 0, 0, 0 }
> };
>
> @@ -168,6 +169,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
> case 'X':
> grub_util_set_kexecute ();
> break;
> + case 't':
> + free (tpm_dev);
> + tpm_dev = xstrdup (arg);
> + break;
>
> case ARGP_KEY_ARG:
> {
> @@ -276,6 +281,9 @@ main (int argc, char *argv[])
>
> dir = xstrdup (dir);
>
> + if (tpm_dev)
> + grub_util_tpm_open (tpm_dev);
> +
> /* Start GRUB! */
> if (setjmp (main_env) == 0)
> grub_main ();
> @@ -283,6 +291,7 @@ main (int argc, char *argv[])
> grub_fini_all ();
> grub_hostfs_fini ();
> grub_host_fini ();
> + grub_util_tpm_close ();
>
> grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
>
> diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
> index 521220b49..1db24fde7 100644
> --- a/grub-core/kern/emu/misc.c
> +++ b/grub-core/kern/emu/misc.c
> @@ -28,6 +28,8 @@
> #include <string.h>
> #include <sys/time.h>
> #include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
>
> #include <grub/mm.h>
> #include <grub/err.h>
> @@ -41,6 +43,8 @@
> int verbosity;
> int kexecute;
>
> +static int grub_util_tpm_fd = -1;
> +
> void
> grub_util_warn (const char *fmt, ...)
> {
> @@ -230,3 +234,50 @@ grub_util_get_kexecute (void)
> {
> return kexecute;
> }
> +
> +grub_err_t
> +grub_util_tpm_open (const char *tpm_dev)
> +{
> + if (grub_util_tpm_fd != -1)
> + return GRUB_ERR_NONE;
> +
> + grub_util_tpm_fd = open (tpm_dev, O_RDWR);
> + if (grub_util_tpm_fd == -1)
> + grub_util_error (_("cannot open TPM device '%s': %s"), tpm_dev, strerror (errno));
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +grub_err_t
> +grub_util_tpm_close (void)
> +{
> + int err;
> +
> + if (grub_util_tpm_fd == -1)
> + return GRUB_ERR_NONE;
> +
> + err = close (grub_util_tpm_fd);
> + if (err != GRUB_ERR_NONE)
> + grub_util_error (_("cannot close TPM device: %s"), strerror (errno));
> +
> + grub_util_tpm_fd = -1;
> + return GRUB_ERR_NONE;
> +}
> +
> +grub_size_t
> +grub_util_tpm_read (void *output, grub_size_t size)
> +{
> + if (grub_util_tpm_fd == -1)
> + return -1;
> +
> + return read (grub_util_tpm_fd, output, size);
> +}
> +
> +grub_size_t
> +grub_util_tpm_write (const void *input, grub_size_t size)
> +{
> + if (grub_util_tpm_fd == -1)
> + return -1;
> +
> + return write (grub_util_tpm_fd, input, size);
> +}
> diff --git a/grub-core/lib/tss2/tcg2_emu.c b/grub-core/lib/tss2/tcg2_emu.c
> new file mode 100644
> index 000000000..6bf4195d7
> --- /dev/null
> +++ b/grub-core/lib/tss2/tcg2_emu.c
> @@ -0,0 +1,54 @@
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2024 SUSE LLC
> + * Copyright (C) 2024 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/efi/api.h>
> +#include <grub/efi/efi.h>
> +#include <grub/efi/tpm.h>
Hmmm... Do we really need that stuff for grub-emu?
> +#include <grub/mm.h>
> +#include <grub/emu/misc.h>
> +
> +#include <tss2_buffer.h>
> +#include <tcg2.h>
> +
> +grub_err_t
> +grub_tcg2_get_max_output_size (grub_size_t *size)
> +{
> + if (size == NULL)
> + return GRUB_ERR_BAD_ARGUMENT;
> +
> + *size = GRUB_TPM2_BUFFER_CAPACITY;
> +
> + return GRUB_ERR_NONE;
> +}
> +
> +grub_err_t
> +grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
> + grub_size_t output_size, grub_uint8_t *output)
> +{
> + static const grub_size_t header_size = sizeof (grub_uint16_t) +
> + (2 * sizeof(grub_uint32_t));
Missing space after "sizeof"...
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 32/33] cryptodisk: Document the '-P' option
2024-09-06 9:11 ` [PATCH v19 32/33] cryptodisk: Document the '-P' option Gary Lin via Grub-devel
@ 2024-10-17 18:00 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-17 18:00 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Sep 06, 2024 at 05:11:24PM +0800, Gary Lin via Grub-devel wrote:
> The '-P' option is introduced to support the key protectors framework.
> This commit adds the new option to the GRUB manual.
>
> Signed-off-by: Gary Lin <glin@suse.com>
I think this change should be a part of the patch which introduces
the "-P" option.
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 00/33] Automatic Disk Unlock with TPM2
2024-10-04 6:21 ` Gary Lin via Grub-devel
@ 2024-10-17 18:05 ` Daniel Kiper
0 siblings, 0 replies; 82+ messages in thread
From: Daniel Kiper @ 2024-10-17 18:05 UTC (permalink / raw)
To: Gary Lin
Cc: grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Fri, Oct 04, 2024 at 02:21:35PM +0800, Gary Lin via Grub-devel wrote:
> On Thu, Oct 03, 2024 at 05:58:41PM +0200, Daniel Kiper wrote:
> > On Fri, Sep 06, 2024 at 05:10:52PM +0800, Gary Lin via Grub-devel wrote:
> > > GIT repo for v19: https://github.com/lcp/grub2/tree/tpm2-unlock-v19
> > >
> > > This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
> > > Hernan Gatta to introduce the key protector framework and TPM2 stack
> > > to GRUB2, and this could be a useful feature for the systems to
> > > implement full disk encryption.
> > >
> > > To support TPM 2.0 Key File format(*2), patch 1~7,9-16 are grabbed from
> > > Daniel Axtens's "appended signature secure boot support" (*3) to import
> > > libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
> > > 4.19.0 instead of 4.16.0 in the original patch.
> >
> > I tried to build this patch set and got this errors:
> >
> > ./configure --target=i386 --with-platform=pc ...
> > make
> > ...
> > tests/asn1/tests/Test_overflow.c: In function ‘test_overflow’:
> > tests/asn1/tests/Test_overflow.c:48:50: error: left shift of negative value [-Werror=shift-negative-value]
> > unsigned long num = ((long) GRUB_UINT_MAX) << 2;
> > ^~
> > cc1: all warnings being treated as errors
> >
> > May I ask you to test 32-bit builds, e.g. as above, before posting next
> > versions of patches?
> >
> Sorry for that. Will do the 32-bit test build for the next version.
>
> > I will send more comments in the following days. I will drop you a line
> > when you can repost the patch set.
> >
> Okay.
Go ahead... I will review updated documentation in v20.
Daniel
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v19 30/33] tpm2_key_protector: Add grub-emu support
2024-10-17 17:57 ` Daniel Kiper
@ 2024-10-18 9:31 ` Gary Lin via Grub-devel
0 siblings, 0 replies; 82+ messages in thread
From: Gary Lin via Grub-devel @ 2024-10-18 9:31 UTC (permalink / raw)
To: Daniel Kiper
Cc: Gary Lin, grub-devel, Hernan Gatta, Daniel Axtens, shkhisti,
jaskaran.khurana, christopher.co, daniel.mihai, jaredz,
development, jejb, mchang, patrick.colp, Stefan Berger,
Vladimir Serbinenko
On Thu, Oct 17, 2024 at 07:57:11PM +0200, Daniel Kiper wrote:
> On Fri, Sep 06, 2024 at 05:11:22PM +0800, Gary Lin via Grub-devel wrote:
> > As a preparation to test tpm2_key_protector with grub-emu, the new
> > option, --tpm-device, is introduced to specify the TPM device for
> > grub-emu so that grub-emu can share the emulated TPM device with
> > the host.
>
> s/can share the emulated TPM device with/can access an emulated TPM device from/?
>
> > Since grub-emu can directly access the device node on host, it's easy to
>
> s/device node/device/
>
Will fix them in the next version.
> > implement the essential TCG2 command submission function with the
> > read/write functions and enable tpm2_key_protector module for grub-emu,
> > so that we can further test TPM2 key unsealing with grub-emu.
> >
> > Signed-off-by: Gary Lin <glin@suse.com>
> > Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
>
> Otherwise Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>...
>
> ... and three nits below...
>
> > ---
> > grub-core/Makefile.core.def | 3 ++
> > grub-core/kern/emu/main.c | 11 ++++++-
> > grub-core/kern/emu/misc.c | 51 +++++++++++++++++++++++++++++++++
> > grub-core/lib/tss2/tcg2_emu.c | 54 +++++++++++++++++++++++++++++++++++
> > include/grub/emu/misc.h | 5 ++++
> > 5 files changed, 123 insertions(+), 1 deletion(-)
> > create mode 100644 grub-core/lib/tss2/tcg2_emu.c
> >
> > diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> > index 97ae4e49b..40427165e 100644
> > --- a/grub-core/Makefile.core.def
> > +++ b/grub-core/Makefile.core.def
> > @@ -2574,7 +2574,9 @@ module = {
> > common = lib/tss2/tpm2_cmd.c;
> > common = lib/tss2/tss2.c;
> > efi = lib/efi/tcg2.c;
> > + emu = lib/tss2/tcg2_emu.c;
> > enable = efi;
> > + enable = emu;
> > cppflags = '-I$(srcdir)/lib/tss2';
> > };
> >
> > @@ -2586,6 +2588,7 @@ module = {
> > common = commands/tpm2_key_protector/tpm2key_asn1_tab.c;
> > /* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */
> > enable = efi;
> > + enable = emu;
> > cppflags = '-I$(srcdir)/lib/tss2 -I$(srcdir)/lib/libtasn1-grub';
> > };
> >
> > diff --git a/grub-core/kern/emu/main.c b/grub-core/kern/emu/main.c
> > index 855b11c3d..c10838613 100644
> > --- a/grub-core/kern/emu/main.c
> > +++ b/grub-core/kern/emu/main.c
> > @@ -55,7 +55,7 @@
> > static jmp_buf main_env;
> >
> > /* Store the prefix specified by an argument. */
> > -static char *root_dev = NULL, *dir = NULL;
> > +static char *root_dev = NULL, *dir = NULL, *tpm_dev = NULL;
> >
> > grub_addr_t grub_modbase = 0;
> >
> > @@ -108,6 +108,7 @@ static struct argp_option options[] = {
> > {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
> > {"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
> > {"kexec", 'X', 0, 0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0},
> > + {"tpm-device", 't', N_("DEV"), 0, N_("Set TPM device."), 0},
>
> s/Set/set/? It looks all messages start with lowercase...
>
Oh, yes, it should start with lowercase.
> > { 0, 0, 0, 0, 0, 0 }
> > };
> >
> > @@ -168,6 +169,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
> > case 'X':
> > grub_util_set_kexecute ();
> > break;
> > + case 't':
> > + free (tpm_dev);
> > + tpm_dev = xstrdup (arg);
> > + break;
> >
> > case ARGP_KEY_ARG:
> > {
> > @@ -276,6 +281,9 @@ main (int argc, char *argv[])
> >
> > dir = xstrdup (dir);
> >
> > + if (tpm_dev)
> > + grub_util_tpm_open (tpm_dev);
> > +
> > /* Start GRUB! */
> > if (setjmp (main_env) == 0)
> > grub_main ();
> > @@ -283,6 +291,7 @@ main (int argc, char *argv[])
> > grub_fini_all ();
> > grub_hostfs_fini ();
> > grub_host_fini ();
> > + grub_util_tpm_close ();
> >
> > grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
> >
> > diff --git a/grub-core/kern/emu/misc.c b/grub-core/kern/emu/misc.c
> > index 521220b49..1db24fde7 100644
> > --- a/grub-core/kern/emu/misc.c
> > +++ b/grub-core/kern/emu/misc.c
> > @@ -28,6 +28,8 @@
> > #include <string.h>
> > #include <sys/time.h>
> > #include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> >
> > #include <grub/mm.h>
> > #include <grub/err.h>
> > @@ -41,6 +43,8 @@
> > int verbosity;
> > int kexecute;
> >
> > +static int grub_util_tpm_fd = -1;
> > +
> > void
> > grub_util_warn (const char *fmt, ...)
> > {
> > @@ -230,3 +234,50 @@ grub_util_get_kexecute (void)
> > {
> > return kexecute;
> > }
> > +
> > +grub_err_t
> > +grub_util_tpm_open (const char *tpm_dev)
> > +{
> > + if (grub_util_tpm_fd != -1)
> > + return GRUB_ERR_NONE;
> > +
> > + grub_util_tpm_fd = open (tpm_dev, O_RDWR);
> > + if (grub_util_tpm_fd == -1)
> > + grub_util_error (_("cannot open TPM device '%s': %s"), tpm_dev, strerror (errno));
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +grub_err_t
> > +grub_util_tpm_close (void)
> > +{
> > + int err;
> > +
> > + if (grub_util_tpm_fd == -1)
> > + return GRUB_ERR_NONE;
> > +
> > + err = close (grub_util_tpm_fd);
> > + if (err != GRUB_ERR_NONE)
> > + grub_util_error (_("cannot close TPM device: %s"), strerror (errno));
> > +
> > + grub_util_tpm_fd = -1;
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +grub_size_t
> > +grub_util_tpm_read (void *output, grub_size_t size)
> > +{
> > + if (grub_util_tpm_fd == -1)
> > + return -1;
> > +
> > + return read (grub_util_tpm_fd, output, size);
> > +}
> > +
> > +grub_size_t
> > +grub_util_tpm_write (const void *input, grub_size_t size)
> > +{
> > + if (grub_util_tpm_fd == -1)
> > + return -1;
> > +
> > + return write (grub_util_tpm_fd, input, size);
> > +}
> > diff --git a/grub-core/lib/tss2/tcg2_emu.c b/grub-core/lib/tss2/tcg2_emu.c
> > new file mode 100644
> > index 000000000..6bf4195d7
> > --- /dev/null
> > +++ b/grub-core/lib/tss2/tcg2_emu.c
> > @@ -0,0 +1,54 @@
> > +/*
> > + * GRUB -- GRand Unified Bootloader
> > + * Copyright (C) 2024 SUSE LLC
> > + * Copyright (C) 2024 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/efi/api.h>
> > +#include <grub/efi/efi.h>
> > +#include <grub/efi/tpm.h>
>
> Hmmm... Do we really need that stuff for grub-emu?
>
Ah, those headers are not necessary.
> > +#include <grub/mm.h>
> > +#include <grub/emu/misc.h>
> > +
> > +#include <tss2_buffer.h>
> > +#include <tcg2.h>
> > +
> > +grub_err_t
> > +grub_tcg2_get_max_output_size (grub_size_t *size)
> > +{
> > + if (size == NULL)
> > + return GRUB_ERR_BAD_ARGUMENT;
> > +
> > + *size = GRUB_TPM2_BUFFER_CAPACITY;
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +
> > +grub_err_t
> > +grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
> > + grub_size_t output_size, grub_uint8_t *output)
> > +{
> > + static const grub_size_t header_size = sizeof (grub_uint16_t) +
> > + (2 * sizeof(grub_uint32_t));
>
> Missing space after "sizeof"...
>
Will fix them in the next version.
Gary Lin
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 82+ messages in thread
end of thread, other threads:[~2024-10-18 9:32 UTC | newest]
Thread overview: 82+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-06 9:10 [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 01/33] posix_wrap: tweaks in preparation for libtasn1 Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 02/33] libtasn1: import libtasn1-4.19.0 Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 03/33] libtasn1: disable code not needed in grub Gary Lin via Grub-devel
2024-09-06 9:10 ` [PATCH v19 04/33] libtasn1: replace strcat() with strcpy() in _asn1_str_cat() Gary Lin via Grub-devel
2024-10-03 16:03 ` Daniel Kiper
2024-09-06 9:10 ` [PATCH v19 05/33] libtasn1: replace strcat() with _asn1_str_cat() Gary Lin via Grub-devel
2024-10-03 16:06 ` Daniel Kiper
2024-09-06 9:10 ` [PATCH v19 06/33] libtasn1: adjust the header paths in libtasn1.h Gary Lin via Grub-devel
2024-10-03 16:08 ` Daniel Kiper
2024-09-06 9:10 ` [PATCH v19 07/33] libtasn1: Use grub_divmod64() for division Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 08/33] libtasn1: fix the potential buffer overrun Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 09/33] asn1_test: include asn1_test.h only Gary Lin via Grub-devel
2024-10-04 15:38 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 10/33] asn1_test: rename the main functions to the test names Gary Lin via Grub-devel
2024-10-04 15:43 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 11/33] asn1_test: remove 'verbose' and the unnecessary printf() Gary Lin via Grub-devel
2024-10-04 16:28 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 12/33] asn1_test: print the error messages with grub_printf() Gary Lin via Grub-devel
2024-10-04 16:31 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 13/33] asn1_test: return either 0 or 1 to reflect the results Gary Lin via Grub-devel
2024-10-04 16:34 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 14/33] asn1_test: use the grub-specific functions and types Gary Lin via Grub-devel
2024-10-04 16:36 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 15/33] libtasn1: compile into asn1 module Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 16/33] asn1_test: test module for libtasn1 Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 17/33] libtasn1: Add the documentation Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 18/33] key_protector: Add key protectors framework Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 19/33] tss2: Add TPM2 buffer handling functions Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 20/33] tss2: Add TPM2 types and Marshal/Unmarshal functions Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 21/33] tss2: Add TPM2 Software Stack (TSS2) support Gary Lin via Grub-devel
2024-09-18 3:14 ` Stefan Berger
2024-09-18 7:28 ` Gary Lin via Grub-devel
2024-10-01 14:48 ` Daniel Kiper
2024-10-04 6:14 ` Gary Lin via Grub-devel
2024-10-07 6:06 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 22/33] key_protector: Add TPM2 Key Protector Gary Lin via Grub-devel
2024-09-18 15:22 ` Stefan Berger
2024-09-19 7:45 ` Gary Lin via Grub-devel
2024-09-19 15:05 ` Stefan Berger
2024-09-20 2:17 ` Gary Lin via Grub-devel
2024-10-16 15:44 ` Daniel Kiper
2024-10-17 2:11 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 23/33] cryptodisk: Support key protectors Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 24/33] util/grub-protect: Add new tool Gary Lin via Grub-devel
2024-10-16 16:04 ` Daniel Kiper
2024-10-17 2:39 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 25/33] tpm2_key_protector: Support authorized policy Gary Lin via Grub-devel
2024-10-16 16:08 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 26/33] tpm2_key_protector: Implement NV index Gary Lin via Grub-devel
2024-10-16 16:11 ` Daniel Kiper
2024-10-17 2:54 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 27/33] cryptodisk: Fallback to passphrase Gary Lin via Grub-devel
2024-10-16 16:14 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 28/33] cryptodisk: wipe out the cached keys from protectors Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 29/33] diskfilter: look up cryptodisk devices first Gary Lin via Grub-devel
2024-10-16 16:19 ` Daniel Kiper
2024-10-17 2:56 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 30/33] tpm2_key_protector: Add grub-emu support Gary Lin via Grub-devel
2024-10-17 17:57 ` Daniel Kiper
2024-10-18 9:31 ` Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 31/33] tests: Add tpm2_key_protector_test Gary Lin via Grub-devel
2024-09-06 9:11 ` [PATCH v19 32/33] cryptodisk: Document the '-P' option Gary Lin via Grub-devel
2024-10-17 18:00 ` Daniel Kiper
2024-09-06 9:11 ` [PATCH v19 33/33] docs: Document TPM2 key protector Gary Lin via Grub-devel
2024-09-13 14:25 ` Stefan Berger
2024-09-20 8:16 ` Gary Lin via Grub-devel
2024-09-20 13:42 ` Stefan Berger
2024-10-04 6:12 ` Gary Lin via Grub-devel
2024-09-13 14:32 ` [PATCH v19 00/33] Automatic Disk Unlock with TPM2 Stefan Berger
2024-09-16 2:24 ` Gary Lin via Grub-devel
2024-09-16 3:35 ` Gary Lin via Grub-devel
2024-09-16 17:42 ` Stefan Berger
2024-09-17 19:23 ` Stefan Berger
2024-09-18 3:12 ` Gary Lin via Grub-devel
2024-09-18 3:05 ` Gary Lin via Grub-devel
2024-09-18 14:09 ` Stefan Berger
2024-09-18 15:17 ` Stefan Berger
2024-09-19 7:59 ` Gary Lin via Grub-devel
2024-10-03 15:58 ` Daniel Kiper
2024-10-04 6:21 ` Gary Lin via Grub-devel
2024-10-17 18:05 ` Daniel Kiper
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.