Регистры PCR, то есть Platform Configuration Registers, это небольшие ячейки памяти внутри криптографического чипа TPM 2.0, которые хранят не данные, а криптографический конденсат всей цепочки загрузки компьютера. Смысл конструкции на удивление приземлённый: вместо того чтобы читать и проверять каждый байт прошивки, загрузчика и ядра (что по времени и по угрозам невозможно), чип получает от каждого этапа загрузки хеш и впечатывает этот хеш в себя операцией, которую невозможно откатить и подделать. В результате один короткий 32-байтный вектор в каждом регистре описывает целую историю старта машины. Дальше в статье разобрано, как работает расширение PCR, как над ним устроен measured boot, почему BitLocker привязывает ключ диска именно к этим регистрам, где механизм честно ломается физически и почему сообщение о запросе ключа восстановления после обновления BIOS это не сбой, а исправная сработка защиты.
Что такое PCR и почему их двадцать четыре
TPM 2.0 по спецификации обязан предоставлять минимум 24 регистра PCR, и на практически всех платформах именно столько и есть. Каждый регистр это просто буфер размером с хеш используемого алгоритма, обычно 32 байта для SHA-256, иногда 20 байтов для SHA-1, если банк SHA-1 вообще включён. Ключевое свойство регистра не размер, а правила записи прямого присваивания нет. Процессор, прошивка, загрузчик, операционная система никто не может записать в PCR произвольное значение. Допустимы только две операции: сброс при старте платформы в строго определённое начальное значение и extend, о котором ниже.
Регистры распределены по номинам: пример статического распределения описан в спецификациях PC Client Platform Firmware Profile. PCR 0 измеряет базовую прошивку, то есть SRTM, core root of trust for measurement, сам код, который стартует measured boot. PCR 2 собирает код опциональных ROM и расширений, PCR 4 загрузчик и попытки его вызова, PCR 7 фиксирует конфигурацию безопасной загрузки: состояние Secure Boot, bkheys (pk, kek, db, dbx), и конкретные сертификаты, которым доверена цепочка. Именно семёрка стала главным рабочим инструментом Microsoft, потому что она описывает не сами двоичные файлы, а политику доверия. Отдельные диапазоны 8-15 зарезервированы для операционной системой, 16-23 доступны приложениям и тестам, 17-22 используется динамическим корнем доверия (DRTM), если платформа его поддерживает.
Операция extend или почему порядок необратим
Механика PCR держится на одной формуле: PCR_new = Hash(PCR_old || дайджест). Символ || здесь означает конкатенацию: берётся текущее содержимое регистра, к нему справа приписывается новый хеш, и всё это целиком хешируется заново. Результат кладётся обратно в тот же регистр, старое значение безвозвратно теряется.
Из этого следуют сразу три фундаментальных свойства. что нельзя вернуться. Найти по известному PCR_new такое PCR_old, которое с заданным дайджестом дало бы этот результат, означает сломать односторонность SHA-256, чего наука пока не умеет. Второе свойство зависимость от порядка. Extent A потом B и extent B потом A дают разные состояния, потому что хеш не коммутативен. Если атакующий подменит очередность компонентов или вставит свой этап между штатными, итоговый вектор неминуемо изменится. Свойство монотонность: регистр только растёт историей, нельзя «замести следы», откатив PCR к прошлому состоянию. После холодного сброса регистра в ноль любой вставленный злонамеренный компонент навсегда остаётся в финальном хеше.
Именно поэтому перезаписать цепочку незаметно нельзя в принципе. Атакующий может загрузить свой bootkit, но bootkit обязан сначала измерить себя (или следующий этап измерит его), и этот измерительный след осядет в PCR. Единственная альтернатива убедить TPM принять другую последовательность невозможна без взлома самого чипа, потому что extend выполняется внутри кремния, а не в оперативной памяти, к которой у атакующего есть доступ на взломанной системе.
Measured boot по этапам загрузки
Измеренная загрузка устроена как эстафета, где каждый участник перед передачей эстафеты фиксирует отпечаток следующего. Упрощённо поток выглядит так (это единственный нумерованный список в статье):
- Core Root of Trust for Measurement, неизменяемый стартовый блок прошивки, первым делом измеряет сам себя и следующий модуль прошивки (PEI, драйверы DXE) и делает extend в PCR 0.
- Прошивка измеряет свою конфигурацию: значения NVRAM-переменных, таблицы, настройки Setup, и расширяет соответствующие PCR 1 и другие.
- Перед запуском любого опционального ROM (видеоадаптер, сетевой контроллер, RAID) прошивка хеширует его образ и расширяет PCR 2.
- Boot manager выбирает загрузчик ОС, хеширует его и расширяет PCR 4, заодно фиксируя параметры выбранной записи загрузки.
- Цепочка доверия Secure Boot измеряется отдельно: состояние политики и набор доверенных ключей уходят в PCR 7.
- Загрузчик ОС измеряет ядро, boot-драйверы и критичные параметры командной строки, расширяя выделенные ему PCR.
- Операционная система продолжает свои измерения (ELAM-антивирус, конфигурация запуска) и при необходимости логирует события в журнал измерений.
Параллельно с PCR существует событийный лог (TCG log): текстовый по сути журнал, где каждому extend соответствует запись «что именно измерялось». Сам лог хранится в обычной памяти и защиты от подделки не имеет; его достоверность проверяется криптографически: берутся записи лога по порядку, replay выполняет те же extend локально, и итог сравнивается с реальными значениями PCR. Совпало доверие к логу есть. Не совпало лог подделан.
Почему это «температура по больнице» в хорошем смысле
Классический подход к проверке целостности читать код и сверять хеши файлов на диске. Проблема очевидна: если система уже скомпрометирована, чтение контролируется вредоносом, который отдаёт проверяющему «правильные» байты из теневой копии. PCR решает проблему тем, что вообще отказывается читать. Вместо построчного анализа система фиксирует агрегированный отпечаток состояния платформы, роспись, слепленную из всего, что реально выполнялось с момента старта.
Это и есть та самая «средняя температура», только с противоположным знаком: агрегат здесь не размывает сигнал, а концентрирует его. Любое изменение любого компонента цепочки прошивка другой версии, иной параметр Setup, чужой опциональный ROM, переписанный загрузчик, модифицированное ядро неминуемо меняет конечные значения PCR. Проверяющему не нужно знать, какой именно компонент изменился, чтобы констатировать факт: «эта машина загрузилась не так, как ожидалось». Для проверки состояния флота из тысяч машин это идеальная экономика: вместо аудита содержимого сравниваются короткие векторы с эталонными значениями, снятыми с заведомо здоровой конфигурации.
При этом механизм честен в своих границах. PCR фиксирует, что загрузилось, а не хорошее ли оно. Если штатное, подписанное, измеренное ядро содержит уязвимость, measured boot молча зафиксирует его как «известное и ожидаемое». Защита от эксплуатации уязвимости задача уже других слоёв: signature enforcement, VBS, Credential Guard. Measured boot отвечает только за вопрос «та ли это конфигурация, которую утвердил владелец».
Sealing и BitLocker привязка ключа к состоянию
Sealing это операция TPM, при которой секрет связывается с политикой, требующей конкретных значений PCR. Секрет хранится не на диске, а внутри объектов TPM, и чип отпечатывает (unseal) его только если текущие PCR совпадают с зафиксированными при seal. Никакие права администратора, никакой доступ к диску на другой машине это не обойти, потому что решение принимает кремний.
BitLocker в конфигурации по умолчанию для современных устройств использует именно эту схему: ключ шифрования тома запечатан с привязкой к PCR, в зависимости от поколения Windows это исторически PCR 0 для классической схемы и PCR 7 (плюс PCR 11 для собственных компонентов Windows) для современной, где измеряется политика Secure Boot, а не сами бинарники. Практический эффект: пока загрузка идёт по штатному пути, TPM на нужном этапе отпечатывает ключ, система стартует без вопросов. Как только что-то в цепочке изменилось, PCR не совпали, и unseal отказан. Извлечь ключ иначе нельзя: он никогда не покидает TPM в открытом виде.
Сюда же относится and remote аттестация для предприятий. TPM умеет криптографически подписать текущие значения PCR (операция quote) ключом attestation identity key, происхождение которого заверяет чип. Удалённый сервер получает quote, replay событийного лога, сверяет с эталонами и принимает решение: допускать машину к корпоративным ресурсам или нет. Это основа Zero-устройств: доступ выдаётся не по паролю пользователя, а по доказанному состоянию платформы.
Наконец, endorsement key, мастер-ключ, вшитый в TPM производителем и заверенный его сертификатом, нужен как якорь личности чипа. Сам EK никогда не подписывает пользовательские данные и не используется напрямую в протоколах именно ради приватности: если бы каждая аттестация подписывалась EK, все сервисы мира могли бы связать машины между собой по одному и тому же ключу. Вместо этого через протоколы активации (или схему DAA) выдаются временные AIK, анонимные для разных верификаторов. Приватность встроена в архитектуру: чип доказывает подлинность, не раскрывая уникальную личность.
Почему «BitLocker запросил ключ после обновления BIOS» это фича
Сценарий знаком каждому администратору: пользователь обновил прошивку, перезагрузился и вместо рабочего стола увидел экран с запросом 48-значного ключа восстановления. С точки зрения удобства это раздражает, но с точки зрения модели угроз это ровно то поведение, за которое платили.
Обновление UEFI меняет байты прошивки, а значит меняет измерения, попадающие в PCR 0, и, в зависимости от обновления, может поменять сертификаты Secure Boot, влияющие на PCR 7. Для TPM такая загрузка неотличима от атаки: чип видит лишь, что последовательность extend привела к незнакомым значениям, и честно отказывает в unseal. Альтернатива была бы страшнее: если бы TPM как-то «понимал», что обновление это «хорошее» изменение, то злоумышленник с bootkit претворился бы «хорошим изменением» тем же приёмом. Кремний не различает намерения, и это его главное достоинство.
Правильная процедура для администратора отсюда очевидна: перед обновлением прошивки приостановить защиту (suspend BitLocker), выполнить обновление, дать системе перезагрузиться и перерасширить PCR, затем возобновить защиту; ключ восстановления всегда хранить отдельно от машины. Реакция «BitLocker сломался» на самом деле означает «BitLocker исправно отработал против случайного нарушения ожидаемой конфигурации».
Границы защиты и аппаратные контратаки
TPM закрывает программную подмену цепочки, но угрозы физического уровня остаются. Классический приём холодная загрузка (cold boot): содержимое DRAM недолго сохраняется после снятия питания, и при быстрой перезагрузке на подконтрольную среду атакующий может считать остаточные данные, включая ключи, которые ОС уже сняла из TPM и держала в памяти. Важно различать: PCR и запечатанные секреты внутри чипа при этом не утекают, утекают уже отпечатанные ключи.
Митигации известны и внедряются постепенно. Первая scrubbing памяти прошивкой при старте и функция MemoryOverwriteRequest (MOR): надёжный сигнал от ОС к прошивке о принудительной очистке DRAM перед любой новой загрузкой, чтобы агент перезагрузки получал только нули. Вторая шифрование памяти на уровне контроллера. Отдельная тема физическая шина TPM: у дискретных чипов ранние исследования показывали сниффинг LPC/SPI, ответом стали параметризованные сессии с шифрованием ответов, а современный тренд fTPM и Pluton, где TPM встроен в SoC и физической шины для перехвата нет вовсе. Ограничение extend здесь тоже работает на защиту: даже при физическом доступе монотонность регистра не даёт замести следы после факта, остаются только атаки «до измерения», которые и перекрываются корнем доверия.
Собирая всё вместе: PCR это дешёвый, математически жёсткий механизм конденсации доверия. Он не читает код, не судит о его качестве и не пытается быть антивирусом он просто навсегда запоминает, в каком порядке и что именно исполнялось, и делает это расширение несмываемым. Всё остальное запечатывание ключей, аттестация, досадные, но спасительные экраны восстановления лишь следствия этой одной формулы: PCR_new равен хешу от старого плюс новый этап.