In my first post on the subject, I indicated calculating PCR[18]
and PCR[19]
was significantly easier than PCR[17]
. If you read my last post on calculating PCR[17]
you’ll see why. Since then I’ve gone through and sorted out calculating the remaining two PCRs and it is in fact pretty easy (few!).
PCR[18]
Unlike PCR[17]
, 18 and 19 are mostly just hashes of boot modules. Unfortunately the MLE Developers Guide again is a bit vague here and maybe a bit misleading even. I’m starting to think that the guide on the Intel website is out of date.
The state of PCR[18]
is defined in section 1.9.2. From the text:
PCR 18 will be extended with the SHA-1 hash of the MLE, as reported in the
SinitMleData.MleHash field.
This is true but it’s only the first extend operation. There can be a second and by default (default tboot behavior) there is. The second hash is of the first boot module after the MLE. The is the module tboot executes after the SINIT.
So what’s the MLE (Measured Launch Environment) anyways? The MLE is the thing that does the measured launch. Pretty much it’s the code that executes GETSEC[SENTER]
and hands control over to the SINIT ACM, that’s tboot. After a successful measured launch this hash will be in the TXT heap in the SINIT to MLE data table. The field is called the MleHash
.
Like I said in my first post: this isn’t about blindly trusting the hashes in the heap though. We want to be able to isolate the thing being measured so if the MLE is tboot then we should be able to take the SHA1 hash of the tboot binary and get the same value … or not. There’s actually a structure within tboot that defines the MLE. The hash of this structure is what’s in the MleHash filed of the SINIT to MLE data table.
There’s already a stand-alone program in the tboot code to calculate this hash for use in the LCP. I’ve not yet looked too deep into how this is calculated though. For now, if you’re interested, you can use this tool to calculate the MleHash and compare this to the data reported in your TXT heap or the txt-stat output. Mine looks like this:
$ ./lcp_mlehash -c "logging=serial,vga,memory" ~/txt-test/modules/tboot.gz 5b d5 12 72 1e 07 5e 31 4d 8d e5 2e 5f b9 10 04 d4 00 e7 27
A very important thing to note here is that we pass not only the module to this program but the arguments passed to it as well.
So the MLE Dev Guide indicates that PCR[18]
will be extended with the MleHash we’ve just now calculated. But if you check the status of your PCR[18]
after a measured launch you’ll realize that it can’t be calculated with just the MleHash. So the MLE Dev Guide isn’t really the best documentation for this stuff I guess. You’re much better off reading the README in the tboot sources.
In the README it’s clearly stated that PCR[18]
is extended not only with the MleHash but also with the hash of the first boot module. The bit that’s missing of course is a description of how modules are hashed. The exact algorithm for doing this isn’t in the Dev Guide or the README though, it’s in the tboot source code in the file tboot/common/policy.c
.
A module hash is simply the hash of the command line passed two the module concatinated with the module itself (remember the two parameters passed to the lcp_mlehash above). There isn’t much to processing the command line but if you’re interested you can check out the code. I’ve added a utility called module-hash
to automate this to the pcr-calc
library. Using the notation we’ve been using up till now this could be represented as:
module_hash = SHA1 (cmdline | module)
You can invoke the utility to perform this calculation like so:
module-hash --cmdline tboot.cmdline --module tboot.gz
Combine this with the MleHash and the full PCR[18]
calculation is as follows:
PCR[18]_1 = sha1 (PCR[18]_0 | MleHash) PCR[18]_2 = sha1 (PCR[18]_1 | sha1 (cmdline | module))
there are two extends required to calculate PCR[18]
. And as a reminder: PCR[18]_0
is the PCR before any extend operations so it contains 20 bytes of 0’s. In my example setup the module that’s hashed and extended into PCR[18]
after the MLE is just the linux kernel file vmlinuz
.
The pcr-calc
project has a pcr18
utility too that wraps the MleHash and the hashing of the module for convenience. It gets the MleHash from the heap still but the next logical step is to calculate it directly from the tboot binary and the commandline. Invoke pcr18
like so:
$ pcr18 --module vmlinuz --cmdline vmlinuz.cmd txtheap.bin
The --cmdline
argument is a file containing a single line of text which is parsed as the parameters to the module.
PCR[19]
PCR[19]
is just as trivial to calculate and again the Dev guide is little help. There’s nothing mentioned of this PCR in the Dev Guide but the LCP dictates what gets hashed and stored in it.
The default tboot policy extends PCR[19]
with the hash of all remaining modules. That’s all of the boot modules that aren’t an SINIT ACM, the MLE or the first module.
This leaves the initrd on my system (yours may be different and may have more than one module). If the module is compressed it must be decompressed before it’s hashed. The calculation of PCR[19]
can be described as follows:
PCR[19]_1 = sha1 (PCR[19]_0 | sha1 (cmdline_1 | module_1)) PCR[19]_n = sha1 (PCR[19]_n-1 | sha1 (cmdline_n | module_n))
Remember that module_0
is tboot so it’s measured as part of PCR[18]
so we start here with cmdline_1
and module_1
.
The pcr-calc
project has yet another program pcr19
that automates the calculation of PCR[19]
. The calling convention is a bit awkward here and I’ll probably have to come up with something better:
$ pcr19 module1.cmd,module1 module2.cmd,module2
The arguments are all positional. They’re ordered pairs of files with the first being a file containing the command line text and the second being the module itself. This means your file paths can’t have commas in them.
Conclusion
When I started out on this quest to pre-calculate the DRTM PCRs as populated by the Intel TXT hardware and tboot I knew this would be painful but I didn’t realize how much. It really was an exercise in masochism. Now that I’ve jumped through the hoops and done the digging necessary to understand the process, I’ve got a pretty good understanding of what’s required to move to the next phase of this project.
My prevous work with OE and the meta-measured layer is the groundwork. It produces a system image that will do a TXT measured launch but the PCR values after boot are still a mystery. I had hoped to be able to calculate all of these measurements in the build, but access to the TXT heap from the target device isn’t realistic. From the work discussed above however, it looks like PCR[18]
and PCR[19]
can be calculated reliably.
The remaining work is to calculate the MleHash, though the existing tool in tboot is extremely close to what we need. Combined with the tools from pcr-calc
this is likely sufficient. All of this will need to be combined and integrated into the meta-measured layer likely as part of an image class. Sounds like my next task is to clean this stuff up and revive meta-measured.