RTC Anti-rollback/Implementation

From OLPC
Jump to navigation Jump to search

OFW implementation

Bootup procedure

  • RTCAR is performed only in secure mode.
  • The RTCAR recovery test (see #rtc-timestamp recovery procedure) is performed just after the test for firmware update in Firmware_security#Process.
  • The RTCAR boot test is performed only if the "ak" tag is not present in Manufacturing data.
  • The RTCAR boot test is performed just prior to the test for a valid lease in Firmware_security#Process. In the presence of rollback or corruption, OFW will boot from actos/actrd. Otherwise it will boot from either runos/runrd or actos/actrd according to the presence or absence of a valid activation lease. In other words, apparent RTC rollback is treated as a missing or invalid lease.
  • OFW records the status of the RTCAR check by creating properties in the device tree /chosen node as follows:
    • Property name: rtc-timestamp Property value: Null-terminated ASCII string containing the value of the most recent preexisting (prior to the current boot) timestamp. The timestamp format is http://en.wikipedia.org/wiki/ISO_8601 , using the UTC timezone, e.g. "20110324T093447\0". The date and time come directly from the contents of the real time clock registers, with no offsetting or other adjustment beyond conversion from the internal BCD storage format into decimal ASCII. If there is no previously-recorded timestamp, as would be the case if rtc-status contained "empty", the rtc-timestamp property will not be present.
    • Property name: rtc-count Property value: Null-terminated ASCII string containing a decimal number indicating the number of timestamps that have been recorded up to and including the most recent preexisting (prior to the current boot) one. It is possible, though unlikely, that rtc-timestamp could be missing even though rtc-count is nonzero. It is also possible, and similarly unlikely, that rtc-count could be zero with rtc-timestamp present. The real guarantee is that rtc-count will increment on each boot. In the absence of RTCAR recovery operations, the rtc-count value should accurately reflect the number of timestamps that have been recorded over the lifetime of the system.
    • Property name: rtc-status Property value: Null-terminated ASCII string containing one of the following values:
      • "ok" - the RTC timestamp area is valid and the RTC value is more recent than the last timestamp. In this case, OFW will create a new timestamp recording the current RTC value, for use on the next boot. The timestamp that is exported via the "rtc-timestamp" property is the previously-recorded one, not the new one.
      • "empty" - the RTC timestamp area was initially empty, i.e. no timestamps were recorded in it. In this case, OFW will automatically initialize the timestamp area and create a new timestamp recording the current RTC value, for use on the next boot. This case is not considered as a "rollback", so OFW will not force the use of actos/actrd. The "rtc-timestamp" property will be absent, as no previously-recorded timestamp information is available.
      • "residue" - the RTC timestamp area contained some data, but there was a problem with it, such as an invalid checksum or junk after the last timestamp. This case is considered as a possible attack, so OFW forces the use of actos/actrd. OFW does not record a new timestamp. The "rtc-timestamp" property may be present or absent, according to whether or not there was at least one valid timestamp.
      • "rollback" - the RTC timestamp area is valid format-wise, but the most recent timestamp is later than the current RTC time. This case is considered a possible rollback attempt, so OFW forces the use of actos/actrd. OFW does not record a new timestamp. The "rtc-timestamp" property contains the most recent timestamp, i.e. the one that was more recent than the current RTC value.

rtc-timestamp recovery procedure

OFW will repair the timestamp area if a suitable RTC timestamp reset signature is present in /security, as detailed below.

  • The name of the RTCAR recovery control file is "/security/rtcreset.sig"
  • The signing key is the same one that is used to sign activation leases - either the OLPC key or a deployment-specific key.
  • The file contains one or more "rtc01:"-format records as defined in Firmware_Key_and_Signature_Formats#RTC_Set
  • The "sig01:" or "sig02:" field must have a key signature that matches a public key in the laptop's list of activation keys.
  • The signed data must verify according to that key.
  • The serial number in the rtc01: record must match the laptop's serial number.
  • The currentrtc value in the rtc01: record must match the value that was last reported in the rtc-timestamp property. If the old timestamp is unknown (as might be the case if rtc-status were "residue" and no timestamp were found in the corrupted timestamp area), currentrtc must be set to the value "00000000T000000Z".
  • The nonce value in the rtc01: record must be a 10-digit decimal ASCII number in the range 0000000000..2147483647, indicating the timestamp count value to restore. After insertion of the new timestamp, the new count will be "count+1". In general, nonce should be the same value that was reported in the rtc-count property, or 0000000000 if there was no such property. OFW does not check that nonce matches the value of rtc-count that is implied by the previous state of the timestamp area.
  • If all the checks succeed, the newrtc value in the rtc01: record will be recorded as a new timestamp after restoring valid contents in the timestamp recording area.
  • If any of the security checks fails, the timestamp recording area will remain unchanged. In that case, you could recover the timestamp area with a developer key.

initramfs implementation

  • As described above, OFW automatically boots the activation initramfs (actos/actrd) upon detecting rollback or corruption.
  • The initramfs observes the presence of the chosen/rtc-* nodes. If rtc-status is "residue" or "rollback", the following steps are executed. Otherwise, the activation initramfs continues with its "normal" behaviour (where it assumes the laptop lacks activation and looks for an activation lease on USB, SD and wifi).
  • Instead of searching for an activation, the initramfs enters an alternative mode where it looks for a RTC timestamp reset signature via the network.
  • The initramfs connects one by one to all open wifi networks in range, and on each network, connects to the RTC timestamp reset server on the XS predefined addresses on TCP port 191. The logic used here is identical to that used when looking for an activation server.
  • When connected to a server, the initramfs sends the message rtcreset <SERIAL> <RTC-TIMESTAMP> <RTC-COUNT> (e.g. rtcreset SHC01601310 20200101T000113Z 19). This is different from the usual message when an activation is sought, where the message would consist of the laptop serial number alone.
  • The server may then respond with a RTC timestamp reset signature sent as plain-text.
  • If a response is received, the initramfs will save the contents of the response at /security/rtcreset.sig and cleanly reboot the system.
    • Upon reboot, as noted above, the #rtc-timestamp recovery procedure procedure is executed, which will cause OFW to reprogram the rtc-timestamp field based on the response received from the server.
  • If no response is received, the initramfs prints an error message and powers down the XO after a 60 second delay.

Generating a RTC timestamp reset signature

As the RTC timestamp reset signature falls within the regular Firmware security infrastructure, bios-crypto provides the necessary tools in order to generate a valid and signed rtcreset.sig.

Having followed the build/installation instructions documented at bios-crypto, a RTC reset signature can be generated as follows:

 $ ./make-rtcreset.sh --signingkey <SIGNING-KEY> <SERIAL> <UUID> <EXISTING-RTC-TIMESTAMP> <EXISTING-RTC-COUNT> <NEW-RTC-TIMESTAMP>

e.g.

 $ ./make-rtcreset.sh --signingkey lease SHC005007B7 1273E0EC-AEF1-9FF6-45B2-FB706DC24B8D 20120511T024746Z 141 20110511T024746Z

The EXISTING-RTC-TIMESTAMP and EXISTING-RTC-COUNT parameters must be extracted from the XO in question - the rtcreset signature is specific to the target laptop with the current recorded count/timestamp values, and will not work with different values.

The SIGNING-KEY corresponds to the key used to sign the output, in the above example it refers to the keypair of lease.public and lease.private.

The above tool can either be used by hand, or it can form the basis of a more automated system (such as the RTC timestamp reset server).

Delegated signatures

The 'sig02' delegation system can also be used, as follows:

 $ ./make-rtcreset.sh --chain <DELEGATION> --signingkey <SIGNING-KEY> <SERIAL> <UUID> <EXISTING-RTC-TIMESTAMP> <EXISTING-RTC-COUNT> <NEW-RTC-TIMESTAMP>

Where DELEGATION is the path to the delegation file for the laptop in question, and SIGNING-KEY is the key that belongs to the school server in question.

e.g.

 $ ./make-rtcreset.sh --delegation delegation.sig --signingkey school621 SHC005007B7 1273E0EC-AEF1-9FF6-45B2-FB706DC24B8D 20120511T024746Z 141 20110511T024746Z

Testing

Here are some recipes for verifying the correct operation of this feature, using Open Firmware interactive commands. These recipes assume that you can get to the ok prompt, either with a non-secure system or with a developer key.

Testing Rollback Detection

First, enable the use of this feature by creating an "rt" tag in manufacturing data:

 ok " "  " rt" $add-tag

Run the anti-rollback check as follows:

 ok rtc-rollback? .
 0

The first time that you invoke rtc-rollback?, it should return 1, indicating that the timestamp area was empty and has now been initialized. Subsequent invocations should return 0, indicating normal operation.

You can see the relevant properties in /chosen with:

 ok dev /chosen  .properties  dend

To simulate a rollback attack:

 ok clock-node @ iselect  get-time 1- set-time  iunselect

That sets the clock back 1 year (the "1-" decrements the year field). Subsequently:

 ok rtc-rollback? .
 ffffffff
 ok dev /chosen  .properties  dend
 ...
 rtc-status       rollback
 ...

You can put the clock back to normal with:

 ok clock-node @ iselect  get-time 1+ set-time  iunselect

Testing Timestamp Reset

Testing the reset function is complicated because you need to make a signed file, which in turn means that you need access to a private key whose public key is on the test machine. Since I don't have access to the OLPC private keys, I had to inject a test key.

First you need to get a copy of the bios-crypto tools:

 $ git clone git://dev.laptop.org/bios-crypto
 $ cd bios-crypto/build
 $ make

Make a keypair for testing:

 $ ./makekey lease

That creates "lease.public" and "lease.private". Put "lease.public" on a USB FLASH drive so it can be transferred to the test machine:

 $ cp lease.public PATH_TO_USB_FLASH_DRIVE/lease.pub
 $ umount PATH_TO_USB_FLASH_DRIVE

Inject the test key into manufacturing data. The following assumes that there are no deployment-specific keys on the machine, so the "a1" key is available. If "a1" is already in use (use ".mfg-data" to check), you will need to use "a2" instead.

 ok load u:\lease.pub
 ok loaded " a1" $add-key

Now you will need to put the test machine into a state where it thinks a rollback attack has occurred.

 ok clock-node @ iselect  get-time 1+ set-time  iunselect
 ok rtc-rollback? .
 0
 ok clock-node @ iselect  get-time 1+ set-time  iunselect
 ok rtc-rollback? .
 ffffffff
 ok dev /chosen  .properties  dend
 rtc-count                141
 rtc-timestamp            20120511T024746Z
 rtc-status               rollback

What that did was to set the clock ahead by a year, then rtc-rollback? recorded a new timestamp that is a year in the future. Then it set the clock back to the current year, and rtc-rollback? detected an attack because the current (correct) clock is earlier than the year-in-the-future timestamp. The rtc-count and rtc-timestamp properties give us some of the information that we need to construct a signed file to fix the timestamp. The other information that we need is in manufacturing data:

 ok " SN" find-tag drop type
 SHC005007B7
 ok " U#" find-tag drop type
 1273E0EC-AEF1-9FF6-45B2-FB706DC24B8D

Armed with those values (which are machine-specific, so you will have to supply your own values), you can make a signed rtcreset.sig file:

 $ ./make-rtcreset.sh --signingkey lease SHC005007B7 1273E0EC-AEF1-9FF6-45B2-FB706DC24B8D 20120511T024746Z 141 20110511T024746Z

Note that the next-to-last field - 20110511T024746Z - is similar to the first date field ("2012...") except that the year was manually restored to the current year - 2011 instead of 2012. That final date field is the timestamp that will be restored into the test machine; it can be any date/time that is before the current RTC date/time.

The make-rtcreset.sh script writes the result into the output file rtcreset.sig. Copy it onto the USB FLASH drive for transfer to the test machine:

 $ mkdir -p PATH_TO_USB_FLASH_DRIVE/security
 $ cp rtcreset.sig PATH_TO_USB_FLASH_DRIVE/security
 $ umount PATH_TO_USB_FLASH_DRIVE

Insert the USB FLASH drive into the test machine and:

 ok load-crypto . get-my-sn .
 0 0
 ok " u:" dn-buf place
 ok ?rtc-update
 Trying u:\security\rtcreset.sig
 RTCRESET found -   Signature valid
 Writing
 e0000

Instead of typing the commands above, you could instead boot the test machine in secure mode, for example by holding down the "X" game button while booting. In secure mode, the recovery procedure happens automatically.

The recovery will only work once because the timestamp in the signed file will no longer match the last recorded timestamp. To re-test the recovery procedure, you must repeat the above steps beginning with simulating the rollback attack, and then make a new signed rtcreset.sig file.