Trusted hardware ================ Isolation in a new threat model: adversary has some physical control of the computer. Subsumes a range of potential attacks. Adversary steals laptop, tries to extract data. Decommissioned laptop disposed, adversary tries to get data from disk. Adversary tampers with server in a data center. Adversary modifies the disk to contain malicious software. Adversary tries to extract secret data from a laptop or server. Two general settings where this threat might show up: The owner of the device is trusted (Bitlocker story, mostly about theft). The owner of the device is untrusted (DRM, cloud computing, smartcards). In general, security against a physical attacker tends to be a gray area. Capable adversary can physically tamper with hardware, extract secrets, etc. Possible to increase attack effort, but few ideas provide a big leap. One of these ideas, though, is this paper's focus: using cryptography. General model for trusted hardware: Trusted chip that we assume hasn't been tampered with. Generally, trusted chip is assumed to be simple, to make it tamper-resistent. Larger devices might be too costly to protect from physical tampering. Everything external to the trusted chip could be controlled by adversary. In particular, includes I/O, memory, and storage. Powerful technique: use cryptography (encryption, authentication). Interesting paper: real-world engineering trade-offs for a security system. Authors fully acknowledge their system is not perfect. Nonetheless, design makes sense for target threat model. Real system: used in Windows Vista onwards. Clean story about using TPM as trusted hardware for physical attacks. More sophisticated systems like SGX are a mix of physical + software threats. What's the problem this paper is trying to solve? Prevent data from being stolen if an attacker physically steals a laptop. How would an attacker get data from stolen laptop, without Bitlocker? Easy: take out the disk; boot from CD and change passwords; etc. Bitlocker's focus: disk encryption, with support from trusted hardware. Why does Bitlocker need trusted hardware at all? Problem: where do the disk encryption (or, decryption) keys come from? Simple approach: user provides key in some form. User might enter password (hashed to produce key, like in Kerberos). Problem: user needs to enter password early in the boot process (BIOS). Problem: passwords are weak, adversary can try to guess the right one. User might plug in a USB drive containing the key. Problem: users don't want to carry around extra USB keys. Problem: users might lose the USB key along with the laptop. Bitlocker's plan: use trusted hardware to get the key. Design trade-off between strong security guarantees and usability. Starting point: how to know your system is running the right software? Often shows up in fixed-function devices: game consoles, Chromebooks, etc. Basic plan: secure boot. Initial boot code comes from ROM, hard-wired at manufacture time. ROM code loads boot loader, checks signature on boot loader. ROM comes with public key that is used for verification. Boot loader loads OS kernel, similarly checks signature. OS kernel checks integrity of all other data it loads. One technical complication: past OS kernel, too costly to check all data. E.g., entire OS image including all libraries. Don't want to load it from disk just to check signature. Instead, need some more efficient plan to authenticate data. One approach: signature on the Merkle root of a file system tree. Check Merkle proofs when loading some data from disk later on. Effectively deferring checks. Another approach we'll look at later: Bitlocker's "poor man's authentication". More efficient but weaker guarantee. Many systems look like this secure boot story. Apple iOS devices. Game consoles (Playstation, Xbox, etc). Chrome OS Verified Boot. [[ Ref: https://www.chromium.org/chromium-os/chromiumos-design-docs/verified-boot ]] UEFI Secure Boot. [[ Ref: https://docs.microsoft.com/en-us/windows/security/information-protection/secure-the-windows-10-boot-process ]] Common challenge: rollback. Boot ROM is stateless, has no idea what version it might have seen before. Naive design could be tricked into booting old OS that has security bugs. One fix: monotonic counter in hardware tracks last seen OS version. More clever trade-offs possible: see Apple iOS case study in later lecture. More flexible alternative: "measured boot". Secure boot supposes you know what key must sign the software. What if the hardware doesn't know what software is good vs bad? Idea: measure what software gets booted. Hash the boot loader, then hash the OS kernel, then hash the OS image, etc. Cannot prevent bad software from loading, but can generate different secrets! System has some durably-stored secret in hardware (same across reboots). When system boots up, it derives a secret key based on its hardware secret. Derivation based on hash of boot loader, OS kernel, etc. OS gets secret key to decrypt its data, to authenticate to remote servers, etc. Booting different OS (e.g., due to malware corruption?) generates different key. Measured boot typically requires a separate trusted measurement chip/device. With secure boot, we were sure all of the code running was "trusted". With measured boot, we don't know what is trusted or not; just measuring it. Main CPU could be running arbitrary code, so how do we do measurements? x86 measured boot approach: TPM (Trusted Platform Module). DRAM /-- BIOS | | CPU --- Northbridge --+-- TPM TPM chip has an ephemeral set of registers (PCR0, PCR1, ..), and a key. Some supported operations (others also exist, but irrelevant here): TPM_extend(m): extend a PCR register, PCRn = SHA1(PCRn || m) TPM_quote(n, m): generate signature of (n -> PCRn, m) with TPM's key TPM_seal(n, PCR_value, plaintext): return ciphertext. TPM_unseal(ciphertext): return plaintext, if PCRn matches PCR_value. Who does the authentication/measurement for measured boot? PCR values get reset to zero only when the entire computer is reset. Important: CPU and TPM must reset together. Important: CPU must jump to BIOS code, which is not tampered with. BIOS code "measures" itself: extends PCR with hash of its code. BIOS code loads boot loader (e.g., Linux grub), measures it (extends PCR with the hash of the boot loader), runs it. Boot loader loads kernel, measures it (extends PCR with H(kernel)), runs it. What can we infer if some PCRn corresponds to a particular chain of hashes? Could be that the right software chain was loaded. Or some software along the way had a bug, was exploited, and adversary issued their own extends from that point forward in the chain. Or the CPU did not start with the BIOS code in the first place. Or the TPM hardware did not reset synchronously with the CPU. [ Turned out to be "easy" on some motherboards: just short out a pin. ] What does this allow us to do? Under assumption that adversary does not tamper with CPU, TPM, or their link. Can prove to others over the network that you're running some software. Use TPM_quote() to get the TPM to sign a message on your behalf. Assumption: remote party trusts your TPM (but not you directly). TPM has its own secret key, HW mfg signs public key, stores cert on TPM. Typically called an "attestation". Good fit for untrusted-owner settings: DRM, cloud compute server, etc. Can communicate with a remote device, and know it's running expected code. E.g., right version of Windows that doesn't allow copying movie data (DRM). E.g., some trustworthy VMM or bootloader for running a VM on a server. Will talk more about cryptographic protocols in later lectures. Can encrypt data in a way that's only accessible to specific software. Use TPM_seal, TPM_unseal. Sealed data can be decrypted only by chosen recipient (PCR). Each TPM has its own randomly-generated key for encryption. E.g., Bitlocker: give key to legitimate OS, let OS verify user's credentials. Bitlocker's TPM mode: key stored in TPM. Idea: store key in the TPM (or rather, seal it using the TPM). Advantage: no need for user to interact with the BIOS. What's the point of TPM-only mode? Key can only be obtained if the machine boots up the same OS (Windows). As a result, security boils down to whatever plan Windows has. One possibility: user has Windows password. Why is this better than the password-in-BIOS approach? 1. No need to enter password twice: in BIOS and in Windows. 2. Windows can rate-limit login attempts, prevent pw guessing. Another possibility: user cannot access sensitive data directly. User might have to access sensitive data via privileged process. Privileged process will not divulge entire data set. What gets measured at boot in BitLocker? Two partitions on disk. First partition contains BitLocker's bootstrapping code. Second partition contains encrypted data ("OS volume"). First partition measured at boot. BitLocker's key sealed with first partition's PCR measurement. Why not measure the second partition? Changes frequently. Need a more efficient "authentication" plan. Expectation: adversary won't be able to meaningfully change it. What if we need to upgrade the first partition? One possibility: re-seal key with new PCR value before upgrade. What if we need to upgrade laptops? Or, laptop died and need to recover? Disk encryption key is stored encrypted with a recovery password. (Or, stored in Active Directory encrypted with admin's password.) User can type in their recovery password to gain access to disk. How do we encrypt the disk once we have the key? Encrypt disk blocks (sectors) one-at-a-time. Why one-at-a-time? Atomicity, performance. Potential problem: integrity (adversary can modify sectors on disk). Why is this a problem for a disk encryption scheme? Why is it insufficient to do secure boot (check signatures on code)? What are the options for ensuring integrity? Ideally, store a MAC (~keyed hash) for the sector somewhere on disk. Recall, disks write sectors at a time: need one MAC per sector. Store MAC in adjacent sector: effectively cut space by a factor of 2, and might also break atomicity if disk crashes between 2 sector writes. Store MAC in a table elsewhere: two seeks (and breaks atomicity). Store MACs for group of sectors nearby: breaks atomicity. Where can we store MACs for integrity? Buy really expensive disks (NetApp, EMC) that have jumbo sectors. "Enterprise" disks have 520-byte sectors, instead of standard 512. Extra 8 bytes used to store checksums, transaction IDs, etc. Could be used to store MAC. Not going to fly for common machines. BitLocker approach: "poor-man's authentication" Assume adversary cannot change the ciphertext in a "useful" fashion. I.e., cannot have a predictable effect on the plaintext. When would this work or not? Works if applications detect or crash when important data is garbled. Must be true at sector-level, which attacker can corrupt separately. Probably true for code: random instructions will raise an exception. Worst case for data: 1 bit (e.g., "require login?") alone in a sector. Adversary can guess random ciphertexts, see when that bit changes. If application doesn't notice other bits corrupted, game over. Hopefully this is not how the registry is constructed, so maybe OK.. How does Bitlocker achieve poor-man's authentication? Tweak symmetric encryption scheme. Goal: localized changes to ciphertext influence entire block. Existing schemes don't have this property (e.g., encrypt 128 bits at a time). So, Bitlocker introduces a shuffling step; details not terribly relevant here. What about freshness? Harder to achieve: need to have some state that can't be rolled back. Strawman: hash all blocks, store hash in TPM. Problem: updates require re-hashing entire disk, slow. Idea: tree of hashes (Merkle tree). Even that is often too expensive to update. Potential attacks on BitLocker? Not intended to be a perfect security solution, by design. Hardware attacks: DMA, cold boot attacks, .. Security vulnerabilities in Windows (buffer overflows, root access). Rolling back disk blocks to an old version (i.e., violate freshness). Adversary likely doesn't have interesting old blocks. Hard (expensive in terms of performance) to defend against. No vulnerabilities found in design so far (8 yrs), modulo threat model. Attacks mostly focus on extracting key from Windows kernel's memory. Hardware attacks: DMA via devices like Firewire. Attack interconnect between CPU and TPM. Software attacks: install a kernel module as administrator; get memory dump. Requires first bypassing access control in Windows in some way. Goal was to increase cost of attack, and BitLocker appears to succeed at it. Similar ideas show up in Intel SGX for protecting memory against physical attacks. Encrypt memory contents. Also do authentication and freshness "for real". Physical attacks subsume software attacks. SGX uses memory encryption to also protect against OS being compromised. Hardware provides a new mode of execution called an "enclave". Enclave memory gets encrypted, authenticated. If untrusted OS tampers with enclave memory, just a special case of physical attack. Alternative to BitLocker's sector encryption: filesystem-level encryption. E.g., ecryptfs in Linux, used by Ubuntu's home directory encryption. FS can solve atomicity/consistency problems. FS can find space for extra MACs, random IVs to prevent IV reuse, etc. FS might require much more code to be "measured" into the TPM. FS comes up much later in the boot process. Requires TPM re-sealing for FS upgrades, driver upgrades, etc. FS might not interpose on swapping/paging. FS harder to deploy (changes to FS, cannot deploy incrementally). What other security properties might users want from memory/disk encryption? Data secrecy: adversary that gets access to disk cannot get data. Bitlocker mostly gets this, modulo being deterministic. Data integrity: adversary cannot replace data on disk without detection. Bitlocker relies on "poor man's authentication". Data freshness: adversary cannot roll back to an old version without det. No protection against this in Bitlocker. Works for their threat model.