Restrict unsealed output file permissions

pull/603/head
Aidan Garske 2026-09-10 10:20:32 -07:00
parent 338f56fedc
commit 863f0f900b
2 changed files with 133 additions and 3 deletions

View File

@ -1013,9 +1013,64 @@ if [ $NO_FILESYSTEM -eq 0 ]; then
./examples/seal/seal sealedkeyblob.bin mySecretMessage >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "seal failed! $RESULT" && exit 1
./examples/seal/unseal message.raw sealedkeyblob.bin >> $TPMPWD/run.out 2>&1
rm -f message.raw
for FILE_STATE in new existing; do
if [ "$FILE_STATE" = "existing" ]; then
chmod 666 message.raw
RESULT=$?
[ $RESULT -ne 0 ] && \
echo -e "chmod unseal output failed! $RESULT" && exit 1
fi
# Unsealed data must stay owner-only even under a permissive umask.
(umask 000 && ./examples/seal/unseal message.raw sealedkeyblob.bin) \
>> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -ne 0 ] && \
echo -e "unseal to $FILE_STATE file failed! $RESULT" && exit 1
grep -qx "mySecretMessage" message.raw
RESULT=$?
[ $RESULT -ne 0 ] && \
echo -e "unsealed data did not match! $RESULT" && exit 1
FILE_MODE=$(stat -c %a message.raw 2>/dev/null)
if [ -z "$FILE_MODE" ]; then
FILE_MODE=$(stat -f %Lp message.raw 2>/dev/null)
fi
[ "$FILE_MODE" != "600" ] && \
echo -e "$FILE_STATE unseal output permissions were $FILE_MODE," \
"expected 600" && exit 1
done
rm -f unseal-target.raw unseal-symlink.raw unseal-hardlink.raw
printf '%s\n' "doNotOverwrite" > unseal-target.raw
ln -s unseal-target.raw unseal-symlink.raw
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "unseal failed! $RESULT" && exit 1
[ $RESULT -ne 0 ] && echo -e "create unseal symlink failed! $RESULT" && \
exit 1
./examples/seal/unseal unseal-symlink.raw sealedkeyblob.bin \
>> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -eq 0 ] && echo -e "unseal to symlink should fail!" && exit 1
grep -qx "doNotOverwrite" unseal-target.raw
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "unseal followed symlink! $RESULT" && exit 1
rm -f unseal-symlink.raw
ln unseal-target.raw unseal-hardlink.raw
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "create unseal hardlink failed! $RESULT" && \
exit 1
./examples/seal/unseal unseal-hardlink.raw sealedkeyblob.bin \
>> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -eq 0 ] && echo -e "unseal to hardlink should fail!" && exit 1
grep -qx "doNotOverwrite" unseal-target.raw
RESULT=$?
[ $RESULT -ne 0 ] && echo -e "unseal followed hardlink! $RESULT" && exit 1
rm -f unseal-target.raw unseal-hardlink.raw
./examples/seal/unseal . sealedkeyblob.bin >> $TPMPWD/run.out 2>&1
RESULT=$?
[ $RESULT -eq 0 ] && echo -e "unseal to directory should fail!" && exit 1
rm -f sealedkeyblob.bin
if [ $WOLFCRYPT_ENABLE -eq 1 ] && [ $WOLFCRYPT_RSA -eq 1 ]; then

View File

@ -28,6 +28,21 @@
#include <wolftpm/tpm2_wrap.h>
#include <stdio.h>
#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES) && \
!defined(WOLFTPM_CUSTOM_STDIO) && \
(defined(WOLFTPM2_NO_WOLFCRYPT) || defined(XFDOPEN)) && \
(defined(__linux__) || defined(__APPLE__) || defined(__unix__))
#define WOLFTPM_UNSEAL_POSIX_FILE_IO
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#ifndef XFDOPEN
#define XFDOPEN fdopen
#endif
#ifndef XCLOSE
#define XCLOSE close
#endif
#endif
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(NO_FILESYSTEM)
@ -41,6 +56,66 @@
/* --- BEGIN TPM2.0 Unseal example --- */
/******************************************************************************/
#ifndef NO_WRITE_TEMP_FILES
static XFILE openPrivateFileWrite(const char* filename)
{
#ifdef WOLFTPM_UNSEAL_POSIX_FILE_IO
int fd;
int openFlags;
struct stat fileStat;
#ifndef O_NOFOLLOW
struct stat pathStat;
#endif
XFILE fp;
openFlags = O_WRONLY | O_CREAT;
#ifdef O_CLOEXEC
openFlags |= O_CLOEXEC;
#endif
#ifdef O_NOFOLLOW
openFlags |= O_NOFOLLOW;
#endif
fd = open(filename, openFlags, S_IRUSR | S_IWUSR);
if (fd < 0)
return XBADFILE;
#ifndef O_NOFOLLOW
/* Confirm open() did not follow a link before changing the file. */
if (lstat(filename, &pathStat) != 0)
goto exit;
#endif
/* Validate before truncating so linked and special files stay untouched. */
if (fstat(fd, &fileStat) != 0 || !S_ISREG(fileStat.st_mode) ||
fileStat.st_uid != geteuid() || fileStat.st_nlink != 1)
goto exit;
#ifndef O_NOFOLLOW
if (!S_ISREG(pathStat.st_mode) ||
pathStat.st_dev != fileStat.st_dev ||
pathStat.st_ino != fileStat.st_ino)
goto exit;
#endif
if (fchmod(fd, S_IRUSR | S_IWUSR) != 0 || ftruncate(fd, 0) != 0)
goto exit;
fp = XFDOPEN(fd, "wb");
if (fp == XBADFILE)
goto exit;
return fp;
exit:
(void)XCLOSE(fd);
return XBADFILE;
#else
/* The custom filesystem controls creation permissions on this path. */
return XFOPEN(filename, "wb");
#endif
}
#endif /* !NO_WRITE_TEMP_FILES */
static void usage(void)
{
printf("Expected usage:\n");
@ -167,7 +242,7 @@ int TPM2_Unseal_Example(void* userCtx, int argc, char *argv[])
#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES)
/* Output the unsealed data to a file */
if (filename) {
fp = XFOPEN(filename, "wb");
fp = openPrivateFileWrite(filename);
if (fp == XBADFILE) {
printf("Error opening %s for writing.\n", filename);
rc = TPM_RC_FAILURE;