###### Thibault Vadon & Luc Riedhauser
# SSHD, FileSystem, Firewall, TPM
## SSHD
### Signature check
- Download `openssh-8.8p1.tar.gz` and `openssh-8.8p1.tar.gz.asc` from www.openssh.com
- When `gpg --verify openssh-8.8p1.tar.gz.asc` :

- So one needs to get the key with `gpg --keyserver keyserver.ubuntu.com --search-keys 7168B983815A5EEF59A4ADFD2A3F414E736060BA` and then `gpg --verify openssh-8.8p1.tar.gz.asc` again.

### Configure package
Use `tar -xvzf openssh-8.8p1.tar.gz` to unzip the package.
1. We need to add hardening options.
Some options are actually already added, one could choose to remove them:
- `--without-stackprotect` : Don't use compiler's stack protection
- `--without-hardening` : Don't use toolchain hardening flags
We can see with `./configure` which flags are used. In this image we see that hardening options are installed.

2. Also, we have to install in a choosen directory. To choose the path for the binaries, use `./configure --prefix=home/lmi/install_PC`.
3. Lets generate code using `make` and `make install`. To check if the files are stripped, use the command `file`.

### For NanoPi
For this installation we need to change the default directory so we do not mix up the version for Intel with the version for arm. We also need to change the host option. Lets use `./configure --host=aarch64-none-linux-gnu --prefix=/home/lmi/install_NanoPi`. Then generate code using `make` and `make install`.
Unfortunatly we get an error :

This error comes from the fact that we need to change the strip command to a strip command that understands executable files intended for the target host (ARM aarch64). After some research, we found that we need to modify the STRIP_OPT variable to `STRIP_OPT=-s --strip-program=/home/lmi/workspace/nano/buildroot/output/host/bin/aarch64-none-linux-gnu-strip` in the `Makefile`.
Then use `make install-nokeys` since we will generate the keys on another host (namely the NanoPi).
To check if the files are stripped, use the command `file`.

### Install on NanoPi
To copy files on NanoPi we will use the `scp` command. It's a ssh command to transfer files.
Files to transfer :
- `/home/lmi/install_NanoPi/sbin/sshd`
- `/home/lmi/install_NanoPi/bin/ssh-keygen`
- `/home/lmi/install_NanoPi/etc/moduli`
- `/home/lmi/install_NanoPi/etc/sshd_config`
These files will be transfered to the directory `/root/sshd` of the NanoPi. You have to create this directory.
Use the command `scp sshd root@192.168.0.100:/root/sshd/`.

Do the same for the others files. Then, one can verify if the files have been copied:

### Create keys
To generate a key, use `./ssh-keygen -b XXXX -t YYYY -f ZZZZ`. Replace `XXXX` with the key length, `YYYY` with the key type and `ZZZZ` with the file location.
Keys to generate and store in `/root/sshd`:
- `rsa` 4096 bits
- `dsa` 1024 bits
- `ecdsa` 521 bits
- `ed25519` 256 bits

### Configure sshd
https://www.ssh.com/academy/ssh/sshd_config
Some modifications must be done in the `sshd_config` file.
The commented values are the default settings. One should override some settings by removing the #.

To start the new ssh server, the old one must be stopped. To find what version of ssh is running, use `ssh -V`. We can see that `Dropbear v2020.81` is the actual version running. To stop it use the command `/etc/init.d/S50dropbear stop`. Then start the ssh deamon by typing: `/root/sshd/sshd -f /root/sshd/sshd_config -h /root/sshd/rsa4096`. It will tell you `Privilege separation user sshd does not exist`. So one needs to add the user sshd: `adduser sshd`. It will ask you for a password (no password is not accepted). We chose `sshd`. Then run `/root/sshd/sshd -f /root/sshd/sshd_config -h /root/sshd/rsa4096` again. This time it will tell you that the directory `/var/empty/` does not exist. Just create it. Now if you run `/root/sshd/sshd -f /root/sshd/sshd_config -h /root/sshd/rsa4096` again, it should start the deamon.
Open a new terminal and type `ssh sshd@192.168.0.100`. It will tell you the following:

One needs to type `ssh-keygen -R 192.168.0.100` to remove the host key of the previous ssh deamon. Then reconnect to the server. After typing the password one should get access to the NanoPi.

One can see the banner, and access to root directory is denied. To disconnect type 'exit'.
On the NanoPi, if one wants to shut down de ssh deamon:

### Server without version (optional)
Typing `nmap -sV -p 22 192.168.0.200` produces the following output:

https://support.hpe.com/hpesc/public/docDisplay?docId=emr_na-c02655633


One can also modify the file `version.h` and recompile everything
```c
/* $OpenBSD: version.h,v 1.92 2021/09/26 14:01:11 djm Exp $ */
#define SSH_VERSION "It is a ssh server without version"
#define SSH_PORTABLE "p1"
#define SSH_RELEASE SSH_VERSION SSH_PORTABLE
```
It will produce the same result. What is important to understand is that the command nmap only recognizes some service versions. If it is not able to recognize the version, it will leave the version field blank. Services can be added here: https://nmap.org/cgi-bin/submit.cgi?new-service.
## FileSystem
### Question 1 : EXT4
#### How does the Kernel know that rootfs is in partition 2 ?
U-boot tells the Kernel where the rootfs is located via the bootargs. One can verify that by looking at the `boot.cmd` file:

Looking at the manual page bootparam, one can read what the argument root does:

So the kernel knows now that rootfs is located in the MMC, block 0, partition 2 which is obviously the second partition of the SD card.
#### Mounting partition 1 of SD card on /mnt
Let's `ls /dev`. One can see that `mmcblk0p1` is present. Let's mount it with `mount -t ext4 /dev/mmcblk0p1 /mnt`. Let's check if the content of partition 1 is in `/mnt`:

> [name=Luc] Dans `/dev` ya mmcblk2*, c'est quoi? C'est la deuxième SD card qui est soudée sur la NanoPI
#### What are the major and minor numbers of the node file managing the SD card ?

The major number is 179 and the minor number is 0. The kernel uses the major number at open time to dispatch execution to the appropriate driver. The minor number is used only by the driver specified by the major number.
### Question 2: btrfs, f2fs, nilfs2, xfs
#### 1.
First of all, one needs to unmount the SD card with `umount /dev/sdb1` and `umount /dev/sdb2`.
Let's start fdisk on `sdb` with `sudo fdisk /dev/sdb`, then type `n` to add a new partition. Then, follow the instructions:

Do the same for the last partition. Then you can print the partition table with the command `p`:

Finally, write the table to disk and exit with the command `w`.
#### 2.
To format the third partition with btrfs execute `sudo mkfs.btrfs /dev/sdb3`.
To format the fourth partition with f2fs execute `sudo mkfs.f2fs /dev/sdb4`. You may need to install f2fs-tools (`sudo dnf install f2fs-tools`).
Let's disconnect the SD card and plug it in again. Type `mount`:

> [name=Luc]Ce qui est bizarre c'est que `umount /dev/sdb3` me donne une erreur: `Error finding object for block device 0:63`. Je suis obligé de le `sudo umount /dev/sdb3`. Pourquoi? Parce que pour btrfs on a besoin d'être super user pour executer certaines commandes.
#### 3.
Using the program skeleton given and after some modifications, we get these outputs.
On btrfs Luc:

On f2fs Luc:

On ext4 Luc:

> [Luc]En vrai ya beaucoup trop de variabilité entre différentes executions du programme. J'imagine que le temps d'accès au bus de données n'est pas toujours le même.
> pour f2fs par exemple j'ai:
> 
> Comment peut-on comparer quoique ce soit avec des valeurs qui changent à ce point.
On btrfs Thibault:

On f2fs Thibault:

It is possible to conclude that btrfs is better to write big files and f2fs is better to write small files. However, comparing these times is not determinist. As shown before, these numbers can vary.
Here are the modifications to be done in `write_skeleton.c`.
```c
int writeSmallFiles()
{
int numfiles = 1000;
int sizeInB = 1024;
char buffer[sizeInB];
FILE *files[numfiles];
for (int i = 0; i < numfiles; i++)
{
char filename[20];
sprintf(filename, "smallFile%d", i);
files[i] = fopen(filename, "w");
for (int j = 0; j < sizeInB; ++j) buffer[j] = 'F';
fwrite(buffer, sizeof(char), sizeInB, files[i]);
}
return 0;
}
int writeBigFile()
{
int numfiles = 1;
int sizeInMB = 1;
char buffer[sizeInMB*1000*1000];
FILE *files[numfiles];
for (int i = 0; i < numfiles; i++)
{
char filename[20];
sprintf(filename, "BigFile%d", i);
files[i] = fopen(filename, "w");
for (int j = 0; j < sizeInMB*1000*1000; ++j) buffer[j] = 'F';
fwrite(buffer, sizeof(char), sizeInMB*1000*1000, files[i]);
}
return 0;
}
```
### Question 3: LUKS, cryptsetup, dmcrypt
#### 1.
First of all, one needs to unmount the SD card with `umount /dev/sdb1` and `umount /dev/sdb2`.
Let's start fdisk on `sdb` with `sudo fdisk /dev/sdb`, then type `n` to add a new partition. Then, follow the instructions:

Finally, write the table to disk and exit with the command `w`.
### Question 3.2: LUKS Test 1
- Let's define `DEVICE=/dev/sdb3` first. Then type `sudo cryptsetup --debug --pbkdf pbkdf2 luksFormat $DEVICE`. Create a passphrase when asked.
- Create a mapping which will create a node file: `sudo cryptsetup --debug open --type luks $DEVICE usrfs1`. The passphrase defined in the previous step is needed.
- Format it as ext4 with `sudo mkfs.ext4 /dev/mapper/usrfs1`
- And mount it to `/mnt/usr` with `sudo mount /dev/mapper/usrfs1 /mnt/usr`. The directory `/mnt/usr` must be created using `cd /mnt/` and `sudo mkdir usr`.
- We can now copy files to the partition. For example: `cp data.txt /mnt/usr`.
- To add another passphrase let's first unmount the partition: `sudo umount /dev/mapper/usrfs1` and remove the node file since we will create a new one with two keys: `sudo cryptsetup close usrfs1`
- Now, let's add a new key with: `sudo cryptsetup luksAddKey $DEVICE` and give a new passphrase when asked.
- Let's check with `sudo cryptsetup luksDump $DEVICE`:

We notice that the second key needs argon2i algorithm. Hence this key may not work on the NanoPi since its RAM is too small.
- To dump the encrypted master key type `sudo cryptsetup luksDump --dump-master-key $DEVICE`:

- Let's dump 1MB of the partition to a file: `sudo dd if=/dev/sdb3 of=dump bs=1024 count=1`
- Using `hexedit dump`, it is possible to see that the master key is still crypted.

- Plug SD card in NanoPi and use`cryptsetup --debug open --type luks /dev/mmcblk0p3 usrfs1`. Once this is done, we need to mount it to `/mnt/usr` with `mount /dev/mapper/usrfs1 /mnt/usr`. Now one has access to the partition:

Do not forget to give the passphrase of the first keyslot since the second one needs argon2 (which may not work).
### Question 3.3: rootfs in a luks partition
- To generate a random passphrase in a file, use `dd if=/dev/urandom of=passphrase bs=64 count=1`. To see the passphrase, use `hexdump passphrase`.

- To initialize a LUKS partition with correct options, use `sudo cryptsetup --debug --pbkdf pbkdf2 --key-size 512 luksFormat $DEVICE passphrase` in the directory where the file "passphrase" is stored.
- Create mapping using `sudo cryptsetup --debug --key-file passphrase open --type luks $DEVICE usrfs1`.
- Format it as ext4 with `sudo mkfs.ext4 /dev/mapper/usrfs1`.
- Finally, copy the rootfs to the partition with `sudo dd if=~/workspace/nano/buildroot/output/images/rootfs.ext4 of=/dev/mapper/usrfs1 bs=4M`.
#### On NanoPi
- First of all, one needs to copy the passphrase file to the NanoPi via `scp passphrase root@192.168.0.200:/root`. ATTENTION, SUPPRIMER LA CLE DE L'ANCIEN SSHD. rm /etc/ssh/none/kwkey
- Then, declare the variable `DEVICE=/dev/mmcblk0p3`.
- Execute `cryptsetup --debug --key-file /root/passphrase open --type luks $DEVICE usrfs1`
- Mount it to `/mnt/usr` with `mount /dev/mapper/usrfs1 /mnt/usr`. Now one has access to the partition:

- Let's create a script named `S40luks`:
```shell
#!/bin/sh
#
# mount luks partition
#
DEVICE=/dev/mmcblk0p3
cryptsetup --debug --key-file /root/passphrase open --type luks $DEVICE usrfs1
mount /dev/mapper/usrfs1 /mnt/usr
```
- Copy it to /etc/init.d/ via ssh: `scp S40luks root@192.168.0.200:/etc/init.d`
- And `chmod 755 S40luks` on the nanoPi.
- Restart the nanoPi, and we can see in the following screen shot that the partition has been mounted on startup.

- Still, Let's login and check:

### Question 4: initramfs
- To generate an initramfs, use the code given during the course. The code is given in annex as `buildRamfs.sh`. Note that at line 63, `exec sh` is active but `# exec switch_root /newroot /sbin/init` is commented. This means that the kernel will start a shell instead of mounting the rootfs directly.
- Create the script `bootramfs.cmd` :
```shell=
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
ext4load mmc 0 $kernel_addr_r Image
ext4load mmc 0 $fdt_addr_r nanopi-neo-plus2.dtb
ext4load mmc 0 0x50000000 uInitrd
booti $kernel_addr_r 0x50000000 $fdt_addr_r
```
- Then use `mkimage -C none -A arm64 -T script -d bootramfs.cmd ~/workspace/nano/buildroot/output/images/boot.scr` to generate the boot file. It MUST have the name `boot.scr`.
- Add the following line to your SD card flashing script:

- Once the SD card has been flashed, plugged into the NanoPi, start it and you should obtain this output:

Indeed we have an initram file system. This, before the kernel attaches the rootfs. Now, one can execute `exec switch_root /newroot /sbin/init` to attach the rootfs and start the system as usual:

### Question 5: initramfs-LUKS partition
Let's imagine one wants to work on a crypted rootfs. Therefore one needs to decrypt the LUKS partition before attaching it. This is done in the initramfs with cryptsetup. But we need to install cryptsetup into initramfs. In order to have a functional cryptsetup one needs to add some things to the initramfs script:
- Add a `run` directory to ramfs

- Copy `cryptsetup` to ramfs. Be careful, always use binaries and libraries compiled for your target (NanoPi in this case).

- Copy the passphrase file to ramfs

- Copy the needed libraries to ramfs. To know which libraries cryptsetup is using, one can run `strace` or `strings | grep lib` on the NanoPi. Anyways, cryptsetup will tell you if it misses something at execution.

Now, generate uInitrd again and copy it to the BOOT partition of the SD card again.
From the shell on the initramfs run `cryptsetup --debug --key-file /root/passphrase_luks open --type luks /dev/mmcblk0p3 usrfs1
`
If this was successfull, one should see the nodefile in `/dev/mapper`
Now, let's mount the partition to `/newroot` with `mount /dev/mapper/usrfs1 /newroot`. Of course, this means that `/dev/mmcblk0p2` must not be mounted to `newroot` in the init script.
Finally `exec switch_root /newroot /sbin/init` to have access to the crypted rootfs.
---
The following script generates an `uInitrd` file which initializes automatically a LUKS crypted rootfs partition:
```shell=
#!/bin/bash
ROOTFSLOC=ramfs
cd $HOME
mkdir $ROOTFSLOC
mkdir -p $ROOTFSLOC/{bin,dev,etc,home,lib,lib64,newroot,proc \
,root,sbin,sys,run} #added run for cryptsetup
echo "About to copy the passphrase into root dir"
cd $ROOTFSLOC/root
cp ~/Documents/passphrase_luks .
echo "Passphrase copied"
cd $HOME
cd $ROOTFSLOC/dev
sudo mknod null c 1 3
sudo mknod tty c 5 0
sudo mknod console c 5 1
sudo mknod random c 1 8
sudo mknod urandom c 1 9
sudo mknod mmcblk0p b 179 0
sudo mknod mmcblk0p1 b 179 1
sudo mknod mmcblk0p2 b 179 2
sudo mknod mmcblk0p3 b 179 3
sudo mknod mmcblk0p4 b 179 4
sudo mknod ttyS0 c 4 64
sudo mknod ttyS1 c 4 65
sudo mknod ttyS2 c 4 66
sudo mknod ttyS3 c 4 67
echo "1. nodes done"
cd ../bin
cp ~/workspace/nano/buildroot/output/target/bin/busybox .
ln -s busybox ls
ln -s busybox mkdir
ln -s busybox ln
ln -s busybox mknod
ln -s busybox mount
ln -s busybox umount
ln -s busybox sh
ln -s busybox sleep
ln -s busybox dmesg
cp ~/workspace/nano/buildroot/output/target/usr/bin/strace .
echo "2. bin busybox symblink done"
cd ../sbin
ln -s ../bin/busybox switch_root
echo "2.1. adding cryptsetup"
cp ~/workspace/nano/buildroot/output/target/usr/sbin/cryptsetup .
echo "2.2. added cryptsetup"
echo "3. sbin done"
cd ../lib64
cp ~/workspace/nano/buildroot/output/target/lib64/ld-2.31.so .
cp ~/workspace/nano/buildroot/output/target/lib64/libresolv-2.31.so .
cp ~/workspace/nano/buildroot/output/target/lib64/libc-2.31.so .
ln -s libresolv-2.31.so libresolv.so.2
ln -s libc-2.31.so libc.so.6
ln -s ../lib64/ld-2.31.so ld-linux-aarch64.so.1
echo "3.1 copy and linking lib64 for cryptsetup"
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libcryptsetup.so .
ln -s libcryptsetup.so libcryptsetup.so.12
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libpopt.so .
ln -s libpopt.so libpopt.so.0
cp ~/workspace/nano/buildroot/output/target/lib64/libm-2.31.so .
ln -s libm-2.31.so libm.so.6
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libuuid.so .
ln -s libuuid.so libuuid.so.1
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libblkid.so .
ln -s libblkid.so libblkid.so.1
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libdevmapper.so .
ln -s libdevmapper.so libdevmapper.so.1.02
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libssl.so .
ln -s libssl.so libssl.so.1.1
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libcrypto.so .
ln -s libcrypto.so libcrypto.so.1.1
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libargon2.so .
ln -s libargon2.so libargon2.so.1
cp ~/workspace/nano/buildroot/output/target/lib64/librt-2.31.so .
ln -s librt-2.31.so librt.so.1
cp ~/workspace/nano/buildroot/output/target/lib64/libdl-2.31.so .
ln -s libdl-2.31.so libdl.so.2
cp ~/workspace/nano/buildroot/output/target/usr/lib64/libjson-c.so .
ln -s libjson-c.so libjson-c.so.5
cp ~/workspace/nano/buildroot/output/target/lib64/libpthread-2.31.so .
ln -s libpthread-2.31.so libpthread.so.0
cp ~/workspace/nano/buildroot/output/target/lib64/libatomic.so.1 .
echo "3.2 finished copying and linking for cryptsetup"
cd ../lib
cp ~/workspace/nano/buildroot/output/target/lib64/ld-2.31.so .
ln -s ../lib64/ld-2.31.so ld-linux-aarch64.so.1
echo "4. shared libraries done"
cd ..
cat > init << endofinput
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys
cryptsetup --key-file /root/passphrase_luks open --type luks \
/dev/mmcblk0p3 usrfs1
mount /dev/mapper/usrfs1 /newroot
mount -n -t devtmpfs devtmpfs /newroot/dev
# exec sh
exec switch_root /newroot /sbin/init
endofinput
######
chmod 755 init
echo "5. init done"
cd ..
sudo chown -R 0:0 $ROOTFSLOC
echo "6. change owner done"
cd $ROOTFSLOC
find . | cpio --quiet -o -H newc > ../Initrd
cd ..
gzip -9 -c Initrd > Initrd.gz
mkimage -A arm -T ramdisk -C none -d Initrd.gz uInitrd
echo "7. creation of uInitrd done"
```
> [Luc] Le symbolic linking ne m'est pas très clair. Pourquoi on copie tjrs une_certaine_librairies.so, puis on la link à une_certaine_librairies.so.X.Y.Z. Pourquoi ne pas copier directement la bonne librairie (cad une_certaine_librairies.so.X.Y.Z).
> [Luc] En ce qui concerne les bootargs, dans boot.cmd il y a tjrs `boot=/dev/mmcblk0p2` mais vu que maintenant on boot sur la mmcblk0p3 ce bootarg n'est plus valid. Du coup mon hypothèse est que les bootargs sont ignorés lorsqu'on execute switch_root au lieu de booti.
## TPM
`swtpm socket --tpmstate dir=/home/lmi/swtpm --tpm2 --server type=tcp,port=2321 --ctrl type=tcp,port=2322 --flags not-need-init,startup-clear`
### Question 1 : create-load-save primary keys
- To create a primary key in owner hierarchy with key parameter: rsa 2048 bits, use the command `tpm2_createprimary -C o -G rsa2048 -c o_primary.ctx`.
- To check the handles-transient area use `tpm2_getcap handles-transient`. To check the handles-persistent area, `tpm2_getcap handles-persistent`.
- To flush the handle-transient area use `tpm2_flushcontext -t`.
- To save the primary key to the NV-Ram use `tpm2_evictcontrol -c o_primary.ctx` (or `tpm2_evictcontrol -c 0x80000000` if the index exists in the handles-transient area.)
- Again, to check the handles-transient area use `tpm2_getcap handles-transient`. To check the handles-persistent area, `tpm2_getcap handles-persistent`.
### Question 2 : create-load-save child keys
- To create child key in owner hierarchy with key parameter rsa 2048 bits use `tpm2_create -C o_primary.ctx -G rsa2048 -u child_public -r child_private` if `o_primary.ctx` is your reference file.
- To check the handles-transient area use `tpm2_getcap handles-transient`.

`0x80000000` is the index of primary key
`0x80000001` is the index of child key
- To check the handles-persistent area, `tpm2_getcap handles-persistent`.

`0x81000000` is the index of primary key in the NV-RAM
- To flush the handle-transient area use `tpm2_flushcontext -t`.
- To load child keys to TPM use `tpm2_load -C o_primary.ctx -u child_public -r child_private -c child`.
- To save the child key to the NV-Ram use `tpm2_evictcontrol –c child`.
- Again, to check the handles-transient area use `tpm2_getcap handles-transient`.

- To check the handles-persistent area, `tpm2_getcap handles-persistent`.

### Question 3 : decrypt on TPM
The file `encryptedtex` has been encrypted by the public key `rsa_key.pem`.
To decrypt this file on the TPM:
- Download the rsa_key.pem and encryptedtext from moodle
- Let's cat the rsa_key.pem

- Since a private key can only be imported on the NULL hierarchy, let's run `tpm2_loadexternal -C n -Grsa -r rsa_key.pem -c key.ctx`
- If one executes `tpm2_getcap handles-transient` the index to this key has been added.
- `tpm2_rsadecrypt -c key.ctx -s rsaes encryptedtext -o cleartext` will decrypt `encryptedtext`.
- Let's `cat cleartext`:

Thank you!!
### Question 4 : PCR policy
To simulate how u-boot shoud check the Linux kernel integrity with PCR registers and pcrpolicy:
- Let's find the `Image` file and hash it. The `Image` file is located in `/home/lmi/workspace/nano/buildroot/output/images`.

- After reading `man tpm2_pcrreset`, only PCR 16 and 23 are resetable. So let's reset PCR 16: `tpm2_pcrreset 16`.
- Then, extend PCR16 with `tpm2_pcrextend 16:sha256=962f4b6aeb8b2d74dc595257cb4384fc266283816acc4940622f29ad748bcb6e`
- Let's verify with `tpm2_pcrread sha256:16`:

- `tpm2_createprimary -C o -G rsa2048 -c primary`
- `tpm2_startauthsession -S session`
- `tpm2_policypcr -S session -l sha256:16 -L pcr16_policy`
- `tpm2_flushcontext session`
Until now we have only a hashed PCR16 stored in pcr16_policy file. Now, we need to seal this hash. One may add some secret data to the seal (like a password). Let's just create a file with a success message since we do not need a password to unlock anything.
- `echo "Integrity check SUCCEEDED" > data`
- `tpm2_create -C primary -g sha256 -u pcr16.pub -r pcr16.priv -i data -L pcr16_policy`
- (You may need to flush the RAM with `tpm2_flushcontext -t` before going on)
- `tpm2_load -C primary -u pcr16.pub -r pcr16.priv -c pcr16`
- `tpm2_evictcontrol -c pcr16 0x81010000 -C o`
We've created a sealing object that we stored on the NV-RAM. Now, let's simulate a boot:
- stop swtpm socket and restart it:

- hash `Image` again: `openssl dgst -sha256 Image`
- Then, extend PCR16 with this hash
- And now start a policy session with `tpm2_startauthsession --policy-session -S session`
- `tpm2_policypcr -S session -l sha256:16` to include the PCR value into the session
- `tpm2_unseal -p session:session -c 0x81010000` will unseal the object and return the data.
Let's check. Let's create two scripts, one that creates the policy and another one that performs an integrity check. It is essentially the same code as above but without explanations.
#### `pcr_policy.sh`
```shell=
#!/bin/sh
hash=($(sha256sum Image))
tpm2_pcrreset 16
tpm2_pcrextend 16:sha256=$hash
echo $(tpm2_pcrread sha256:16)
tpm2_createprimary -C o -G rsa2048 -c primary
tpm2_startauthsession -S session
tpm2_policypcr -S session -l sha256:16 -L pcr16_policy
tpm2_flushcontext session
tpm2_create -C primary -g sha256 -u pcr16.pub -r pcr16.priv \
-i data -L pcr16_policy
tpm2_flushcontext -t
tpm2_load -C primary -u pcr16.pub -r pcr16.priv -c pcr16
tpm2_evictcontrol -c pcr16 0x81010000 -C o
echo "created a sealing object and stored it on the NV-RAM!"
```
#### `integrity_test.sh`
```shell=
#!/bin/sh
tpm2_pcrreset 16
tpm2_flushcontext -t
hash=($(sha256sum Image))
tpm2_pcrextend 16:sha256=$hash
tpm2_startauthsession --policy-session -S session
tpm2_policypcr -S session -l sha256:16
tpm2_unseal -p session:session -c 0x81010000
```
If the `Image` file stays the same:

If the `Image` file has changed:

Now let's imagine we update the `Image` file. Next time one boots the system, the policy check fails. It is expected but not wanted. How to bypass this check without compromising the system security?
To achieve this, a trusted administrator must add a PCR signature to the PCR values.
But first let's define a pcr-signed policy. Whether the `Image` file changes or not, the following script will update the sealing object:
```shell=
#!/bin/sh
hash=($(sha256sum Image))
tpm2_pcrreset 16
echo $(tpm2_pcrread sha256:16)
tpm2_pcrextend 16:sha256=$hash
echo $(tpm2_pcrread sha256:16)
echo "create primary owner key"
tpm2_createprimary -C o -G rsa2048 -c primary
echo "pcr policy"
tpm2_startauthsession -S session
tpm2_policypcr -Q -S session -l sha256:16 -L pcr16_policy
tpm2_flushcontext session
echo "rsa key creation"
openssl genrsa -out signing_key_private.pem 2048
openssl rsa -in signing_key_private.pem -out signing_key_public.pem -pubout
echo "create a name for public key (for later use)"
tpm2_loadexternal -G rsa -C o -u signing_key_public.pem -c signing_key.ctx \
-n signing_key.name
echo "signer policy"
tpm2_startauthsession -S session
echo "create a new policy (authorized.policy)"
tpm2_policyauthorize -S session -L authorized.policy -n signing_key.name \
-i pcr16_policy
tpm2_flushcontext session
tpm2_flushcontext -t
echo "creation of the new sealing object"
tpm2_create -g sha256 -u auth_pcr_seal_key.pub -r auth_pcr_seal_key.priv \
-i data -C primary -L authorized.policy
tpm2_flushcontext -t
echo "make it persistent"
tpm2_evictcontrol -C o -c 0x81010001
tpm2_load -Q -C primary -u auth_pcr_seal_key.pub -r auth_pcr_seal_key.priv \
-c auth_pcr_seal_key.ctx
tpm2_evictcontrol -c auth_pcr_seal_key.ctx 0x81010001 -C o
echo "flush RAM"
tpm2_flushcontext -t
echo "sign pcr_policy with the private key"
#you can comment or uncomment this line to see what happens if you
#sign the policy or not
openssl dgst -sha256 -sign signing_key_private.pem -out pcr16_policy.signature \
pcr16_policy
echo "DONE"
```
Let's explain the script above:
1. We define a pcr policy as before
2. We "wrap" the pcr policy into an authorization policy that binds the pcr policy with the administrator's public key. This binding is very important because it garantees that the authorization has been satisfied with the right key (namely the one of the administrator). This will be clearer later.
3. We create a new sealing object as before
4. We make the sealing object persistent.
The following script checks whether the pcr policy change is authorized. If yes, it unseals the sealed object.
```shell=
#!/bin/sh
echo "load external public key of administrator"
tpm2_loadexternal -G rsa -C o -u signing_key_public.pem -c signing_key.ctx \
-n signing_key.name
echo "verifying the signature with public of administrator"
tpm2_verifysignature -c signing_key.ctx -g sha256 -m pcr16_policy \
-s pcr16_policy.signature -t verification.tkt -f rsassa
echo "start a policy-session"
tpm2_startauthsession --policy-session -S session
echo "include the actual pcr value into the session"
tpm2_policypcr -l sha256:16 -S session
echo "authorizing the pcr policy to change with the current \
session IF the signing_key.name corresponds and IF verification.tkt allows it"
tpm2_policyauthorize -S session -i pcr16_policy -n signing_key.name \
-t verification.tkt
tpm2_unseal -p session:session -c 0x81010001
tpm2_flushcontext session
tpm2_flushcontext -t
```
Explanation:
1. We load the administrator's public key
2. We verify the signature on the pcr policy and issue a verification ticket that tells if the pcr policy has been signed by the administrator or not.
3. We authorize the pcr policy to change if the signing key corresponds and if the verification.tkt allows it.
4. We try to unseal the object. If authorization has been granted in the previous step, it should pass. Otherwise, if the `Image` file changed it should fail. Else if the Image file did not change, it should pass.
Now, **the most important thing**: in order to pass the signature verification, the administrator needs to sign the pcr policy with his **private** key if he wants to update the `Image` file:
`openssl dgst -sha256 -sign signing_key_private.pem -out pcr16_policy.signature pcr16_policy`
Let's make some tests:
1. No `Image` file change, no signature of the administrator (should pass):

2. `Image` file change, no signature of the administrator (should fail):

3. No `Image` file change, signature of the administrator (should pass):

4. `Image` file change, signature of the administrator (should pass):

## Annexes
### `buildRamfs.sh`
```shell=
#!/bin/bash
ROOTFSLOC=ramfs
cd $HOME
mkdir $ROOTFSLOC
mkdir -p $ROOTFSLOC/{bin,dev,etc,home,lib,lib64,newroot,proc,root,sbin,sys}
cd $ROOTFSLOC/dev
sudo mknod null c 1 3
sudo mknod tty c 5 0
sudo mknod console c 5 1
sudo mknod random c 1 8
sudo mknod urandom c 1 9
sudo mknod mmcblk0p b 179 0
sudo mknod mmcblk0p1 b 179 1
sudo mknod mmcblk0p2 b 179 2
sudo mknod mmcblk0p3 b 179 3
sudo mknod mmcblk0p4 b 179 4
sudo mknod ttyS0 c 4 64
sudo mknod ttyS1 c 4 65
sudo mknod ttyS2 c 4 66
sudo mknod ttyS3 c 4 67
echo "1. nodes done"
cd ../bin
cp ~/workspace/nano/buildroot/output/target/bin/busybox .
ln -s busybox ls
ln -s busybox mkdir
ln -s busybox ln
ln -s busybox mknod
ln -s busybox mount
ln -s busybox umount
ln -s busybox sh
ln -s busybox sleep
ln -s busybox dmesg
cp ~/workspace/nano/buildroot/output/target/usr/bin/strace .
echo "2. bin busybox symblink done"
cd ../sbin
ln -s ../bin/busybox switch_root
echo "3. sbin done"
cd ../lib64
cp ~/workspace/nano/buildroot/output/target/lib64/ld-2.31.so .
cp ~/workspace/nano/buildroot/output/target/lib64/libresolv-2.31.so .
cp ~/workspace/nano/buildroot/output/target/lib64/libc-2.31.so .
ln -s libresolv-2.31.so libresolv.so.2
ln -s libc-2.31.so libc.so.6
ln -s ../lib64/ld-2.31.so ld-linux-aarch64.so.1
cd ../lib
cp ~/workspace/nano/buildroot/output/target/lib64/ld-2.31.so .
ln -s ../lib64/ld-2.31.so ld-linux-aarch64.so.1
echo "4. shared libraries done"
cd ..
cat > init << endofinput
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t ext4 /dev/mmcblk0p2 /newroot
mount -n -t devtmpfs devtmpfs /newroot/dev
exec sh
# exec switch_root /newroot /sbin/init
endofinput
######
chmod 755 init
echo "5. init done"
cd ..
sudo chown -R 0:0 $ROOTFSLOC
echo "6. change owner done"
cd $ROOTFSLOC
find . | cpio --quiet -o -H newc > ../Initrd
cd ..
gzip -9 -c Initrd > Initrd.gz
mkimage -A arm -T ramdisk -C none -d Initrd.gz uInitrd
echo "7. creation of uInitrd done"
```