Secure Boot 심화
UEFI Secure Boot 신뢰 체인, Authenticode 서명 구조, SBAT 폐기 메커니즘, 커널 모듈 서명, IMA/EVM, TPM Measured Boot, dm-verity — 부트에서 런타임까지의 무결성 보장 체계를 소스 코드 수준에서 분석합니다.
1. Secure Boot 아키텍처 개요
UEFI Secure Boot는 플랫폼 펌웨어가 부팅 과정에서 실행하는 모든 EFI 바이너리의 디지털 서명을 검증하여, 신뢰할 수 없는 코드의 실행을 차단하는 보안 메커니즘입니다. 이 검증은 PKI(Public Key Infrastructure) 기반의 신뢰 체인(Chain of Trust)으로 구현됩니다.
Secure Boot UEFI 변수
Secure Boot의 핵심은 NVRAM에 저장된 인증된(authenticated) UEFI 변수들입니다:
| 변수 | GUID | 역할 | 업데이트 권한 |
|---|---|---|---|
| PK (Platform Key) | EFI_GLOBAL_VARIABLE | 신뢰 체인의 루트. 1개만 존재 | 물리적 접근 + 현재 PK 소유자 |
| KEK (Key Exchange Key) | EFI_GLOBAL_VARIABLE | db/dbx 업데이트 권한 부여 | PK 소유자 |
| db (Signature DB) | EFI_IMAGE_SECURITY_DATABASE | 허용된 서명/해시 목록 | KEK 소유자 |
| dbx (Forbidden DB) | EFI_IMAGE_SECURITY_DATABASE | 폐기된 서명/해시 목록 | KEK 소유자 |
| dbt (Timestamp DB) | EFI_IMAGE_SECURITY_DATABASE | 타임스탬프 서명 검증용 | KEK 소유자 |
| SecureBoot | EFI_GLOBAL_VARIABLE | 활성 상태 (0/1, 읽기 전용) | 펌웨어 |
| SetupMode | EFI_GLOBAL_VARIABLE | Setup 모드 (PK 미설치 시 1) | 펌웨어 |
EFI_VARIABLE_AUTHENTICATION_2 구조체
Secure Boot 변수(db, dbx, KEK 등)는 인증된 업데이트만 허용합니다. 변수를 수정하려면 EFI_VARIABLE_AUTHENTICATION_2 래퍼로 감싸야 합니다:
typedef struct {
EFI_TIME TimeStamp; /* 재전송 방지용 타임스탬프 */
WIN_CERTIFICATE_UEFI_GUID AuthInfo; /* PKCS#7 서명 래퍼 */
} EFI_VARIABLE_AUTHENTICATION_2;
typedef struct {
UINT32 dwLength; /* 인증서 전체 크기 */
UINT16 wRevision; /* WIN_CERT_REVISION = 0x0200 */
UINT16 wCertificateType; /* WIN_CERT_TYPE_EFI_GUID */
EFI_GUID CertType; /* EFI_CERT_TYPE_PKCS7_GUID */
UINT8 CertData[1]; /* DER 인코딩된 PKCS#7 SignedData */
} WIN_CERTIFICATE_UEFI_GUID;
2. Authenticode 서명 형식
UEFI 실행 파일(shimx64.efi, grubx64.efi, vmlinuz.efi)은 PE/COFF(Portable Executable) 형식이며, Authenticode 서명으로 무결성이 검증됩니다.
PE/COFF 서명 구조
/*
* PE 파일의 Authenticode 서명 위치:
*
* ┌─────────────────────────────┐
* │ DOS Header (MZ) │
* ├─────────────────────────────┤
* │ PE Signature ("PE\0\0") │
* ├─────────────────────────────┤
* │ COFF Header │
* ├─────────────────────────────┤
* │ Optional Header │
* │ ├─ Data Directory[4] │◄── Certificate Table 엔트리
* │ │ ├─ VirtualAddress ─────────► 서명 데이터 오프셋
* │ │ └─ Size ──────────────────► 서명 데이터 크기
* ├─────────────────────────────┤
* │ Sections (.text, .data ...) │
* ├─────────────────────────────┤
* │ WIN_CERTIFICATE │◄── Authenticode 서명
* │ ├─ dwLength │
* │ ├─ wRevision (0x0200) │
* │ ├─ wCertificateType │ WIN_CERT_TYPE_PKCS_SIGNED_DATA
* │ └─ bCertificate[] │ PKCS#7 SignedData (DER)
* └─────────────────────────────┘
*/
Authenticode 해시 계산
Authenticode 해시는 일반적인 파일 해시와 다릅니다. 서명 자체와 체크섬 필드를 제외하고 해시를 계산합니다:
/* Authenticode 해시에서 제외되는 영역:
* 1. PE Optional Header의 Checksum 필드 (4 bytes)
* 2. Data Directory[4] Certificate Table 엔트리 (8 bytes)
* 3. WIN_CERTIFICATE 영역 전체 (서명 데이터)
*
* 나머지 모든 바이트가 해시에 포함됨
*/
# sbsign으로 커널 서명
$ sbsign --key db.key --cert db.crt --output vmlinuz.signed vmlinuz.efi
# 서명 검증
$ sbverify --cert db.crt vmlinuz.signed
Signature verification OK
# Authenticode 해시 확인
$ pesign -i vmlinuz.signed -h -P
# SHA-256 해시 출력
# 서명 정보 상세 출력
$ pesign -i vmlinuz.signed -S
---------------------------------------------
certificate address is 0x...
Content was not encrypted.
Content is a detached PKCS#7 signature
Signing time: ...
Signer's common name: My Secure Boot Key
...
서명 도구 비교
| 도구 | 용도 | 특징 |
|---|---|---|
sbsign | PE 바이너리 Authenticode 서명 | sbsigntool 패키지, OpenSSL 기반 |
sbverify | Authenticode 서명 검증 | sbsigntool 패키지 |
pesign | PE 서명/검증/해시 | NSS 기반, Red Hat 계열 |
osslsigncode | Authenticode 서명 (범용) | OpenSSL 기반, 타임스탬프 지원 |
sign-file | 커널 모듈 서명 (PKCS#7) | 커널 빌드 시스템 내장 |
kmodsign | 커널 모듈 서명 (레거시) | sign-file의 이전 이름 |
3. 폐기 메커니즘: dbx와 SBAT
취약점이 발견된 부트로더나 커널을 차단하려면 폐기(revocation) 메커니즘이 필요합니다. UEFI는 두 가지 방식을 제공합니다.
dbx (전통적 방식)
dbx는 차단할 바이너리의 해시 또는 서명 인증서를 기록합니다:
# dbx 현재 내용 확인
$ efi-readvar -v dbx
Variable dbx, length 13588
dbx: List 0, type SHA256
Hash: a4:6f:0c:2e:... # 차단된 바이너리 해시
# dbx 업데이트 (KEK로 서명된 업데이트 적용)
$ efi-updatevar -f dbx-update.auth dbx
# dbx에 새 해시 추가 (Linux fwupd 사용)
$ fwupdmgr get-updates
$ fwupdmgr update
SBAT (Secure Boot Advanced Targeting)
SBAT는 dbx의 확장성 문제를 해결하기 위해 도입된 세대 기반(generation-based) 폐기 메커니즘입니다. 개별 해시 대신 컴포넌트의 보안 세대 번호를 비교합니다.
/* SBAT 메타데이터 (.sbat 섹션, CSV 형식)
*
* shimx64.efi의 .sbat 섹션 예시:
*/
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
shim,4,UEFI shim,shim,1,https://github.com/rhboot/shim
shim.ubuntu,2,Canonical Ltd.,shim,15.8,https://launchpad.net/ubuntu/+source/shim
/* GRUB2의 .sbat 섹션 예시: */
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
grub,4,Free Software Foundation,grub,2.12,https://www.gnu.org/software/grub/
grub.ubuntu,2,Canonical Ltd.,grub2,2.12-1ubuntu1,https://launchpad.net/ubuntu/+source/grub2
SBAT 폐기 정책은 SbatLevel UEFI 변수에 저장됩니다:
# SbatLevel 확인
$ mokutil --list-sbat-revocations
sbat,1,2023022100
shim,2
grub,3
grub.debian,4
# 해석: grub 컴포넌트의 세대 번호가 3 미만인 바이너리는 실행 거부
# → grub 세대 1, 2인 모든 배포판의 GRUB2가 한꺼번에 차단됨
SBAT vs dbx 비교
| 특성 | dbx (해시 기반) | SBAT (세대 기반) |
|---|---|---|
| 식별 방식 | SHA-256 해시 | 컴포넌트명 + 세대 번호 |
| NVRAM 사용량 | 차단 바이너리 수 × 32B | 컴포넌트 수 × ~50B (고정) |
| 확장성 | NVRAM 제한에 빠르게 도달 | 우수 (컴포넌트 단위) |
| 세분화 | 개별 바이너리 | 배포판별 컴포넌트 |
| 적용 대상 | 모든 EFI 바이너리 | .sbat 섹션이 있는 바이너리 |
| 업데이트 | KEK 서명 필요 | SbatLevel 변수 업데이트 |
4. Shim과 MOK 인프라
대부분의 Linux 배포판은 Microsoft UEFI CA가 서명한 Shim 부트로더를 1단계로 사용합니다. Shim은 자체 키 데이터베이스(MOK)를 관리하여 배포판별 2단계 부트로더와 커널을 검증합니다.
Shim 검증 로직
/*
* shim의 EFI 바이너리 검증 순서 (verify_buffer 함수):
*
* 1. dbx (UEFI 폐기 목록) 확인 → 해시/인증서 매치 시 거부
* 2. SBAT 검증 → SbatLevel 미달 시 거부
* 3. db (UEFI 허용 목록) 검증 → 매치 시 허용
* 4. MOK (Machine Owner Key) 검증 → 매치 시 허용
* 5. shim 내장 인증서 검증 → 매치 시 허용
* 6. 모두 실패 → 거부
*/
/* shim 소스 코드에서의 핵심 검증 흐름 (간략화): */
static EFI_STATUS
verify_buffer(char *data, int datasize,
PE_COFF_LOADER_IMAGE_CONTEXT *context)
{
/* Step 1: dbx 확인 (차단 목록) */
if (check_denylist(context, data, datasize) == FOUND)
return EFI_ACCESS_DENIED;
/* Step 2: SBAT 확인 */
if (verify_sbat_section(data, datasize) != EFI_SUCCESS)
return EFI_SECURITY_VIOLATION;
/* Step 3-5: 허용 목록 순서대로 확인 */
if (check_allowlist(context, data, datasize) == FOUND)
return EFI_SUCCESS;
return EFI_ACCESS_DENIED;
}
MOK 관리
# 자체 서명 키 생성
$ openssl req -new -x509 -newkey rsa:2048 -keyout MOK.key \
-out MOK.crt -nodes -days 3650 \
-subj "/CN=My Secure Boot MOK"
# DER 형식으로 변환 (MOK 등록에 필요)
$ openssl x509 -in MOK.crt -outform DER -out MOK.der
# MOK 등록 요청 (다음 부팅 시 MokManager에서 확인)
$ mokutil --import MOK.der
# 비밀번호 입력 → 재부팅 시 MokManager UI에서 동일 비밀번호 입력
# 등록된 MOK 목록 확인
$ mokutil --list-enrolled
[key 1]
SHA1 Fingerprint: ab:cd:ef:...
Subject: CN = My Secure Boot MOK
Issuer: CN = My Secure Boot MOK
# MOK 삭제
$ mokutil --delete MOK.der
# Secure Boot 상태 확인
$ mokutil --sb-state
SecureBoot enabled
SecureBoot validation is enabled in shim
MOK UEFI 변수
| 변수 | 설명 |
|---|---|
MokList | 등록된 MOK 인증서/해시 목록 |
MokListX | MOK 차단 목록 (dbx의 MOK 버전) |
MokNew | 다음 부팅에 등록할 MOK (임시) |
MokDel | 다음 부팅에 삭제할 MOK (임시) |
MokSBState | Shim 수준의 Secure Boot 활성/비활성 |
SbatLevel | SBAT 폐기 정책 |
5. 커널 모듈 서명
Secure Boot 환경에서 커널 모듈은 로드 시 서명이 검증됩니다. 서명 정책은 CONFIG_MODULE_SIG 관련 설정으로 제어합니다.
커널 설정
# 모듈 서명 관련 커널 설정 (Security options → Module signature verification)
CONFIG_MODULE_SIG=y # 모듈 서명 검증 활성화
CONFIG_MODULE_SIG_FORCE=y # 서명 없는 모듈 로드 거부 (Secure Boot 시 필수)
CONFIG_MODULE_SIG_ALL=y # 빌드 시 모든 모듈 자동 서명
# 서명 해시 알고리즘 선택
CONFIG_MODULE_SIG_SHA256=y # SHA-256 (기본)
# CONFIG_MODULE_SIG_SHA384=y
# CONFIG_MODULE_SIG_SHA512=y
# 서명 키 경로
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem" # 서명용 개인키
CONFIG_SYSTEM_TRUSTED_KEYRING=y # 시스템 신뢰 키링
CONFIG_SYSTEM_TRUSTED_KEYS="certs/signing_key.pem" # 빌트인 인증서
# 추가 신뢰 키 소스
CONFIG_SECONDARY_TRUSTED_KEYRING=y # 런타임 추가 키링
CONFIG_INTEGRITY_PLATFORM_KEYRING=y # 플랫폼(Secure Boot) 키링
sign-file 도구
# 커널 빌드 시 자동으로 호출되는 모듈 서명 명령
$ scripts/sign-file sha256 \
certs/signing_key.pem \
certs/signing_key.x509 \
drivers/my_driver.ko
# sign-file 내부 동작:
# 1. 모듈 ELF 바이너리 전체를 SHA-256으로 해시
# 2. 개인키로 PKCS#7 서명 생성
# 3. 서명을 모듈 파일 끝에 추가 (append)
# 4. module_signature 구조체를 맨 끝에 추가
모듈 서명 구조
/* include/linux/module_signature.h */
struct module_signature {
u8 algo; /* 공개키 알고리즘 (RSA, ECDSA ...) */
u8 hash; /* 해시 알고리즘 (SHA-256, SHA-512 ...) */
u8 id_type; /* 키 식별 타입 (PKEY_ID_PKCS7) */
u8 signer_len; /* 서명자 이름 길이 (PKCS#7에서는 0) */
u8 key_id_len; /* 키 ID 길이 (PKCS#7에서는 0) */
u8 __pad[3]; /* 패딩 */
__be32 sig_len; /* 서명 데이터 길이 (빅 엔디안) */
};
/*
* 모듈 파일 레이아웃:
*
* ┌─────────────────────┐
* │ ELF 바이너리 데이터 │ ← 해시 대상
* ├─────────────────────┤
* │ PKCS#7 서명 데이터 │ ← sig_len 바이트
* ├─────────────────────┤
* │ module_signature │ ← 12 바이트 (고정)
* ├─────────────────────┤
* │ MAGIC: "~Module │
* │ signature appended~"│ ← 28 바이트 매직 문자열
* └─────────────────────┘
*/
모듈 서명 검증 흐름
/* kernel/module/signing.c - mod_verify_sig() 간략화 */
int mod_verify_sig(const void *mod, struct load_info *info)
{
struct module_signature ms;
size_t sig_len, modlen = info->len;
/* 매직 문자열 확인 */
if (memcmp(mod + modlen - 28,
"~Module signature appended~\n", 28) != 0)
return -ENODATA; /* 서명 없음 */
/* module_signature 구조체 읽기 */
memcpy(&ms, mod + modlen - 28 - sizeof(ms), sizeof(ms));
sig_len = be32_to_cpu(ms.sig_len);
/* PKCS#7 서명 검증 (시스템 키링의 인증서 사용) */
return verify_pkcs7_signature(
mod, /* 서명 대상 데이터 */
modlen - sig_len - 28 - sizeof(ms), /* 데이터 길이 */
mod + modlen - 28 - sizeof(ms) - sig_len,
sig_len,
VERIFY_USE_SECONDARY_KEYRING, /* .secondary_trusted_keys */
VERIFYING_MODULE_SIGNATURE,
NULL, NULL);
}
/*
* 키링 검색 순서:
* 1. .builtin_trusted_keys (커널 빌드 시 내장된 인증서)
* 2. .secondary_trusted_keys (런타임 추가, MOK에서 import된 키)
* 3. .platform_keyring (UEFI Secure Boot db에서 가져온 키)
*/
모듈 서명 실무 명령
# 모듈 서명 확인
$ modinfo drivers/my_driver.ko | grep sig
sig_id: PKCS#7
signer: Build time autogenerated kernel key
sig_key: AB:CD:12:34:...
sig_hashalgo: sha256
# 서명 유효성 검증 (kmod 도구)
$ modprobe --dump-modversions drivers/my_driver.ko
# 시스템 키링 확인
$ keyctl list %:.builtin_trusted_keys
1 key in keyring:
123456789: ---lswrv 0 0 asymmetri: Build time autogenerated kernel key: ab:cd:...
$ keyctl list %:.secondary_trusted_keys
2 keys in keyring:
234567890: ---lswrv 0 0 asymmetri: My Secure Boot MOK: 12:34:...
# DKMS 모듈 자동 서명 (MOK 키 사용)
# /etc/dkms/framework.conf:
# sign_tool="/etc/dkms/sign_helper.sh"
# mok_signing_key="/var/lib/shim-signed/mok/MOK.priv"
# mok_certificate="/var/lib/shim-signed/mok/MOK.der"
6. Kernel Lockdown LSM
Secure Boot의 신뢰 체인은 커널이 부팅된 후에도 유지되어야 합니다. Lockdown LSM은 커널 무결성을 우회할 수 있는 사용자 공간의 인터페이스를 제한합니다.
Lockdown 레벨
| 레벨 | 설정값 | 제한 범위 |
|---|---|---|
| none | LOCK_NONE | 제한 없음 (Secure Boot 비활성 시) |
| integrity | LOCK_INTEGRITY | 커널 이미지 수정 차단 |
| confidentiality | LOCK_CONFIDENTIALITY | integrity + 커널 정보 유출 차단 |
Lockdown 제한 항목
/* security/lockdown/lockdown.c - Lockdown이 차단하는 기능들 */
/* integrity 레벨에서 차단: */
LOCKDOWN_MODULE_SIGNATURE, /* 서명 없는 모듈 로드 */
LOCKDOWN_DEV_MEM, /* /dev/mem, /dev/kmem 쓰기 */
LOCKDOWN_EFI_TEST, /* EFI 테스트 모드 변수 */
LOCKDOWN_KEXEC, /* 서명 없는 kexec 이미지 */
LOCKDOWN_HIBERNATION, /* 하이버네이션 (이미지 변조 가능) */
LOCKDOWN_PCI_ACCESS, /* PCI BAR 직접 접근 */
LOCKDOWN_IOPORT, /* I/O 포트 직접 접근 */
LOCKDOWN_MSR, /* MSR 쓰기 (/dev/cpu/*/msr) */
LOCKDOWN_ACPI_TABLES, /* 커스텀 ACPI 테이블 로드 */
LOCKDOWN_DEVICE_TREE, /* 디바이스 트리 오버레이 */
LOCKDOWN_PCMCIA_CIS, /* PCMCIA CIS 오버라이드 */
LOCKDOWN_TIOCSSERIAL, /* 시리얼 포트 I/O 변경 */
LOCKDOWN_MODULE_PARAMETERS, /* 위험한 모듈 파라미터 */
LOCKDOWN_MMIOTRACE, /* MMIO 트레이싱 */
LOCKDOWN_DEBUGFS, /* debugfs 접근 */
LOCKDOWN_XMON_WR, /* PowerPC xmon 쓰기 */
LOCKDOWN_BPF_WRITE_USER, /* BPF 사용자 메모리 쓰기 */
LOCKDOWN_DBG_WRITE_KERNEL, /* /proc/kcore 등 커널 메모리 쓰기 */
/* confidentiality 레벨에서 추가 차단: */
LOCKDOWN_KPROBES, /* kprobes 사용 */
LOCKDOWN_TRACEFS, /* tracefs (ftrace) 접근 */
LOCKDOWN_PERF, /* perf 하드웨어 이벤트 */
LOCKDOWN_XMON_RW, /* PowerPC xmon 읽기/쓰기 */
LOCKDOWN_DBG_READ_KERNEL, /* /proc/kcore 등 커널 메모리 읽기 */
LOCKDOWN_BPF_READ_KERNEL, /* BPF 커널 메모리 읽기 */
Lockdown 상태 확인 및 제어
# Lockdown 상태 확인
$ cat /sys/kernel/security/lockdown
none [integrity] confidentiality
# dmesg에서 Lockdown 메시지
$ dmesg | grep -i lockdown
Lockdown: Kernel is locked down from EFI Secure Boot mode; see man kernel_lockdown.7
Lockdown: debugfs: restricted; see man kernel_lockdown.7
Lockdown: tracefs: restricted; see man kernel_lockdown.7
# 커널 커맨드라인에서 Lockdown 설정
# lockdown=integrity (integrity 모드 강제)
# lockdown=confidentiality (confidentiality 모드 강제)
# 커널 설정
CONFIG_SECURITY_LOCKDOWN_LSM=y
CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT=y # Secure Boot 시 자동 integrity
/dev/mem, debugfs, MSR 접근이 차단됩니다. Secure Boot 환경에서 커널 디버깅이 필요하면 lockdown=none 커맨드라인을 사용하거나, Secure Boot를 일시적으로 비활성화해야 합니다. Confidentiality 모드에서는 ftrace, perf, kprobes까지 차단되어 성능 프로파일링도 불가합니다.
7. IMA/EVM — 런타임 무결성 검증
IMA(Integrity Measurement Architecture)와 EVM(Extended Verification Module)은 부팅 이후 파일 시스템 수준에서 무결성을 보장합니다. Secure Boot가 부팅 체인의 무결성을 보장하면, IMA는 런타임 파일 접근의 무결성을 보장합니다.
IMA 아키텍처
/*
* IMA 서브시스템 구조:
*
* ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
* │ IMA-Measure │ │ IMA-Appraise│ │ IMA-Audit │
* │ (측정) │ │ (평가) │ │ (감사) │
* └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
* │ │ │
* └────────────┬───────┴────────────────────┘
* │
* ┌──────┴──────┐
* │ IMA Policy │ ← 어떤 파일을 검증할지 정책
* └──────┬──────┘
* │
* ┌──────┴──────┐
* │ LSM Hook │ ← file_mmap, bprm_check 등
* └──────┬──────┘
* │
* ┌──────┴──────┐
* │ 측정 목록 │ ← /sys/kernel/security/ima/ascii_runtime_measurements
* └──────┬──────┘
* │
* ┌──────┴──────┐
* │ TPM PCR 10 │ ← 측정값 확장 (원격 증명용)
* └─────────────┘
*/
IMA 동작 모드
| 모드 | 설명 | 용도 |
|---|---|---|
| measure | 파일 해시를 측정 목록에 기록 + TPM PCR 확장 | 원격 증명(Remote Attestation) |
| appraise | 파일의 IMA 확장 속성과 실제 해시 비교 | 로컬 무결성 강제 |
| audit | 감사 로그에 해시 기록 | 감사 추적 |
| hash | 확장 속성에 해시만 저장 (서명 없음) | IMA appraise 사전 준비 |
IMA 정책
# 커널 커맨드라인 IMA 옵션
ima_policy=tcb # 기본 TCB 정책 (실행 파일, 라이브러리, 모듈)
ima_policy=appraise_tcb # TCB + appraise 모드
ima_policy=secure_boot # Secure Boot 연동 정책
ima_appraise=enforce # appraise 실패 시 파일 접근 거부
ima_appraise=log # appraise 실패 시 로그만 기록
# 런타임 정책 파일 (/etc/ima/ima-policy 또는 securityfs)
# 정책 형식: action condition [condition ...]
# 실행되는 모든 파일 측정
measure func=BPRM_CHECK
# root가 실행하는 파일의 서명 검증 강제
appraise func=BPRM_CHECK uid=0 appraise_type=imasig
# 커널 모듈 로드 시 서명 검증
appraise func=MODULE_CHECK appraise_type=imasig
# 펌웨어 로드 시 서명 검증
appraise func=FIRMWARE_CHECK appraise_type=imasig
# kexec 커널 이미지 서명 검증
appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig
# 특정 라벨의 파일만 측정 (SELinux 연동)
measure func=FILE_MMAP obj_type=lib_t
# 정책 로드 (securityfs)
$ cat /etc/ima/ima-policy > /sys/kernel/security/ima/policy
IMA 확장 속성
# IMA 확장 속성 확인
$ getfattr -m ^security -d /sbin/init
security.ima=0x... # IMA 서명 또는 해시
security.evm=0x... # EVM HMAC 또는 서명
# IMA 서명 설정 (evmctl 사용)
$ evmctl ima_sign -k /path/to/private_key.pem /sbin/init
# IMA 해시 설정
$ evmctl ima_hash /sbin/init
# 측정 목록 확인
$ cat /sys/kernel/security/ima/ascii_runtime_measurements
10 abc123... ima-sig sha256:def456... /sbin/init
# 위반 목록 확인
$ cat /sys/kernel/security/ima/violations
0
EVM (Extended Verification Module)
EVM은 IMA 확장 속성 자체의 무결성을 보호합니다. 공격자가 security.ima 속성을 위변조하는 것을 방지합니다:
/*
* EVM 보호 대상 확장 속성:
* - security.ima (IMA 해시/서명)
* - security.selinux (SELinux 라벨)
* - security.SMACK64 (SMACK 라벨)
* - security.capability (파일 capability)
*
* EVM은 이 속성들의 HMAC 또는 디지털 서명을
* security.evm에 저장하여 변조를 감지합니다.
*/
# EVM 초기화 (HMAC 모드 — TPM 기반 키)
$ echo 1 > /sys/kernel/security/evm
# EVM 서명 모드 (공개키 기반)
$ evmctl sign -k /path/to/evm-key.pem /sbin/init
# 커널 설정
CONFIG_EVM=y
CONFIG_EVM_ATTR_FSUUID=y # 파일시스템 UUID도 HMAC에 포함
CONFIG_EVM_ADD_XATTRS=y # 추가 xattr을 EVM 보호에 포함
8. TPM과 Measured Boot
Secure Boot(검증 부팅)과 Measured Boot(측정 부팅)는 상호 보완적인 메커니즘입니다. Secure Boot는 신뢰할 수 없는 코드의 실행을 차단하고, Measured Boot는 실행된 코드의 해시를 기록하여 사후 검증을 가능하게 합니다.
TPM PCR (Platform Configuration Register)
/*
* TPM PCR 할당 (TCG PC Client 규격):
*
* PCR 0: SRTM, BIOS, 호스트 플랫폼 Extension, 임베디드 옵션 ROM
* PCR 1: 호스트 플랫폼 설정
* PCR 2: 옵션 ROM 코드
* PCR 3: 옵션 ROM 설정 및 데이터
* PCR 4: IPL 코드 (부트로더), MBR
* PCR 5: IPL 코드 설정 및 데이터
* PCR 6: 상태 전이 및 Wake 이벤트
* PCR 7: Secure Boot 정책 — PK, KEK, db, dbx,
* SecureBoot 변수, 부트 관리자 측정
* PCR 8-15: OS 정의 — Linux에서는:
* PCR 8: GRUB2 커맨드라인/설정
* PCR 9: GRUB2에서 로드한 파일 (커널, initrd)
* PCR 10: IMA 측정 목록
* PCR 11-13: (배포판별 정의)
* PCR 14: MOK 인증서/키
*/
# TPM PCR 값 읽기
$ tpm2_pcrread sha256:0,1,4,7,10
sha256:
0 : 0x3A5F... # BIOS 측정
1 : 0xA2B1... # 플랫폼 설정
4 : 0xF1E2... # 부트로더 측정
7 : 0xC3D4... # Secure Boot 정책
10 : 0xE5F6... # IMA 측정
# PCR 확장(Extend) 원리:
# PCR_new = Hash(PCR_old || measurement)
# → 한번 확장되면 이전 값으로 되돌릴 수 없음 (단방향)
# → 부팅 체인의 모든 측정이 누적된 해시로 표현됨
TCG 이벤트 로그
# 이벤트 로그 확인 (개별 측정 이벤트)
$ tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements
---
- EventNum: 0
PCRIndex: 0
EventType: EV_S_CRTM_VERSION
DigestCount: 1
Digests:
- AlgorithmId: sha256
Digest: "3a5f..."
Event: ...
- EventNum: 15
PCRIndex: 7
EventType: EV_EFI_VARIABLE_DRIVER_CONFIG
Digests:
- AlgorithmId: sha256
Digest: "c3d4..."
Event:
UnicodeName: SecureBoot
VariableData: 01 # Secure Boot 활성
# 커널에서 이벤트 로그 접근
$ ls /sys/kernel/security/tpm0/
binary_bios_measurements # 바이너리 형식
ascii_bios_measurements # 텍스트 형식
원격 증명 (Remote Attestation)
/*
* 원격 증명 흐름:
*
* 1. 검증 서버(Verifier)가 난스(nonce)를 전송
* 2. 클라이언트가 TPM에 Quote 요청:
* - TPM이 PCR 값들에 AIK(Attestation Identity Key)로 서명
* - 난스를 포함하여 재전송 공격 방지
* 3. Quote + 이벤트 로그를 검증 서버에 전송
* 4. 검증 서버가:
* a. AIK 서명 검증
* b. 이벤트 로그를 재연하여 PCR 값 재계산
* c. 재계산된 PCR과 Quote의 PCR 비교
* d. 개별 이벤트를 알려진 양호값(golden values)과 비교
*/
# TPM Quote 생성
$ tpm2_createak -C 0x81010001 -c ak.ctx -G rsa -g sha256
$ tpm2_quote -c ak.ctx -l sha256:0,1,4,7,10 \
-q "nonce_from_verifier" -m quote.msg -s quote.sig
# IMA 측정 목록 (원격 증명에 사용)
$ head -5 /sys/kernel/security/ima/ascii_runtime_measurements
10 a1b2c3... ima-ng sha256:d4e5f6... /sbin/init
10 b2c3d4... ima-ng sha256:e5f6a7... /usr/lib64/ld-linux-x86-64.so.2
10 c3d4e5... ima-ng sha256:f6a7b8... /usr/lib64/libc.so.6
9. dm-verity — 블록 장치 무결성
dm-verity는 device-mapper 타겟으로, 블록 장치 전체의 무결성을 Merkle 트리(해시 트리)로 검증합니다. 읽기 전용 파일시스템의 변조를 런타임에 탐지합니다.
Merkle 트리 구조
/*
* dm-verity Merkle 트리:
*
* ┌─────────┐
* │Root Hash│ ← 커널 커맨드라인 또는 서명된 메타데이터
* └────┬────┘
* ┌─────────┴─────────┐
* ┌───┴───┐ ┌───┴───┐
* │ Hash │ │ Hash │ ← 상위 해시 노드
* └───┬───┘ └───┬───┘
* ┌─────┴─────┐ ┌─────┴─────┐
* ┌──┴──┐ ┌──┴──┐┌──┴──┐ ┌──┴──┐
* │H(B0)│ │H(B1)││H(B2)│ │H(B3)│ ← 리프 해시
* └──┬──┘ └──┬──┘└──┬──┘ └──┬──┘
* ┌──┴──┐ ┌──┴──┐┌──┴──┐ ┌──┴──┐
* │ B0 │ │ B1 ││ B2 │ │ B3 │ ← 데이터 블록 (4KB)
* └─────┘ └─────┘└─────┘ └─────┘
*
* 읽기 요청 시:
* 1. 데이터 블록 읽기
* 2. 블록 해시 계산
* 3. Merkle 트리를 따라 루트까지 검증
* 4. 불일치 시 I/O 오류 반환 또는 시스템 재시작
*/
dm-verity 설정
# 해시 트리 생성
$ veritysetup format /dev/sda2 /dev/sda3
VERITY header information for /dev/sda3
UUID: a1b2c3d4-...
Hash type: 1
Data blocks: 262144
Data block size: 4096
Hash block size: 4096
Hash algorithm: sha256
Salt: abc123...
Root hash: 5f8c3d2a1b4e7f9c0d6a3b8e5f2c1d4a7b0e3f6c9d2a5b8e1f4c7d0a3b6e9f
# verity 장치 활성화
$ veritysetup open /dev/sda2 verified-root /dev/sda3 \
5f8c3d2a1b4e7f9c0d6a3b8e5f2c1d4a7b0e3f6c9d2a5b8e1f4c7d0a3b6e9f
# 마운트
$ mount /dev/mapper/verified-root /mnt -o ro
# 커널 커맨드라인에서 root dm-verity 설정
# root=/dev/dm-0
# dm-mod.create="verified-root,,,ro,0 262144 verity 1 /dev/sda2 /dev/sda3 4096 4096 262144 1 sha256 ROOT_HASH SALT"
# 커널 설정
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y # 루트 해시 서명 검증
CONFIG_DM_VERITY_FEC=y # Forward Error Correction
AVB(Android Verified Boot) 상세
AVB 2.0은 Android 8.0+에서 사용되는 검증 부팅 체계로, 부트로더에서 커널까지의 신뢰 체인(chain of trust)을 구축한다. 핵심 구성 요소는 vbmeta 파티션으로, RSA/ECDSA 서명된 메타데이터에 각 파티션의 해시(hash descriptor) 또는 해시 트리 루트(hashtree descriptor)를 포함한다.
/* VBMeta 구조 (avb_vbmeta_image_header) */
┌───────────────────────┐
│ Header (256B) │ magic: "AVB0", algorithm, key 크기
├───────────────────────┤
│ Authentication Block │ hash + signature (RSA-4096/ECDSA)
├───────────────────────┤
│ Auxiliary Block │ descriptors:
│ ├ hash_descriptor │ boot, init_boot (전체 해시)
│ ├ hashtree_descriptor │ system, vendor (해시 트리 루트)
│ ├ chain_descriptor │ vbmeta_system → 체인 검증
│ └ property_descriptor │ OS version, security patch level
└───────────────────────┘
# 롤백 보호: 각 파티션의 rollback_index가 하드웨어 보호 저장소에 기록
# 이전 버전 이미지 플래시 시 부팅 거부 → 다운그레이드 공격 차단
# 검증 모드:
# - Locked + Verified: 정상 부팅 (서명 검증 필수)
# - Locked + Corrupted: 부팅 거부
# - Unlocked: 개발용 (WARNING 화면 표시)
AVB와 dm-verity 연동, A/B 파티션 구조, 부팅 흐름 등 종합 내용은 Android 커널 — AVB를 참고하라.
10. kexec 서명 검증
kexec는 재부팅 없이 새 커널을 로드하는 메커니즘입니다. Secure Boot 환경에서는 kexec로 로드하는 커널 이미지에도 서명 검증이 필요합니다.
# 서명된 kexec (Secure Boot 환경에서 허용)
$ kexec -l /boot/vmlinuz-signed --initrd=/boot/initrd.img \
--command-line="root=/dev/sda1" --kexec-file-syscall
# kexec_file_load() 시스템 콜에서의 서명 검증:
# 1. PE 헤더 파싱 (bzImage는 PE/COFF 형식)
# 2. Authenticode 서명 추출
# 3. 시스템 키링(.builtin_trusted_keys, .platform_keyring)으로 검증
# 4. IMA 정책에 의한 추가 검증 (func=KEXEC_KERNEL_CHECK)
/* arch/x86/kernel/kexec-bzimage64.c - 서명 검증 흐름 */
static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
{
return verify_pefile_signature(
kernel, kernel_len,
VERIFY_USE_SECONDARY_KEYRING, /* 보조 키링 검색 */
VERIFYING_KEXEC_PE_SIGNATURE); /* 용도 표시 */
}
/* 관련 커널 설정 */
CONFIG_KEXEC_FILE=y # kexec_file_load() 시스템 콜
CONFIG_KEXEC_SIG=y # kexec 서명 검증 활성화
CONFIG_KEXEC_SIG_FORCE=y # 서명 없으면 kexec 거부
CONFIG_KEXEC_BZIMAGE_VERIFY_SIG=y # bzImage 서명 검증
11. 커스텀 키 관리
기업 환경이나 임베디드 시스템에서는 OEM/벤더 키 대신 자체 Secure Boot 키를 사용하여 완전한 신뢰 체인을 구축할 수 있습니다.
커스텀 PK 등록
# 1. 키 생성 (RSA 2048 또는 4096)
# PK (Platform Key)
$ openssl req -new -x509 -newkey rsa:4096 -keyout PK.key \
-out PK.crt -nodes -days 3650 \
-subj "/CN=My Platform Key"
# KEK (Key Exchange Key)
$ openssl req -new -x509 -newkey rsa:4096 -keyout KEK.key \
-out KEK.crt -nodes -days 3650 \
-subj "/CN=My Key Exchange Key"
# db (Signature Database Key)
$ openssl req -new -x509 -newkey rsa:4096 -keyout db.key \
-out db.crt -nodes -days 3650 \
-subj "/CN=My Signature Database Key"
# 2. EFI Signature List (ESL) 형식으로 변환
$ cert-to-efi-sig-list PK.crt PK.esl
$ cert-to-efi-sig-list KEK.crt KEK.esl
$ cert-to-efi-sig-list db.crt db.esl
# 3. 인증된 업데이트 파일 생성 (EFI_VARIABLE_AUTHENTICATION_2)
$ sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl PK.auth
$ sign-efi-sig-list -k PK.key -c PK.crt KEK KEK.esl KEK.auth
$ sign-efi-sig-list -k KEK.key -c KEK.crt db db.esl db.auth
# 4. UEFI Setup Mode에서 키 등록
# (Setup Mode: PK가 없는 상태 → 누구나 변수 수정 가능)
$ efi-updatevar -f db.auth db # db 먼저
$ efi-updatevar -f KEK.auth KEK # KEK 다음
$ efi-updatevar -f PK.auth PK # PK 마지막 (Setup Mode 종료)
# 5. 커널/부트로더를 자체 키로 서명
$ sbsign --key db.key --cert db.crt \
--output vmlinuz.signed vmlinuz
$ sbsign --key db.key --cert db.crt \
--output grubx64.efi.signed grubx64.efi
키 교체 (Key Rotation)
# db 키 교체 시나리오:
# 1. 새 db 키 생성
$ openssl req -new -x509 -newkey rsa:4096 -keyout db-new.key \
-out db-new.crt -nodes -days 3650 \
-subj "/CN=My New DB Key 2026"
# 2. 새 키를 db에 추가 (기존 키 유지, append 모드)
$ cert-to-efi-sig-list db-new.crt db-new.esl
$ sign-efi-sig-list -a -k KEK.key -c KEK.crt db db-new.esl db-append.auth
$ efi-updatevar -a -f db-append.auth db
# 3. 새 키로 커널/부트로더 재서명
$ sbsign --key db-new.key --cert db-new.crt --output vmlinuz.signed vmlinuz
# 4. 검증 후 구 키 제거 (선택)
# → 새 db를 만들어 덮어씀 (구 키 미포함)
# PK 교체:
# 현재 PK로 새 PK를 서명하여 업데이트
$ sign-efi-sig-list -k PK-old.key -c PK-old.crt PK PK-new.esl PK-new.auth
$ efi-updatevar -f PK-new.auth PK
12. 커널 내부 구현
소스 트리 구조
| 경로 | 설명 |
|---|---|
security/integrity/ | IMA/EVM 프레임워크 |
security/integrity/ima/ | IMA 핵심 구현 (정책, 측정, 검증) |
security/integrity/evm/ | EVM 구현 (HMAC/서명) |
security/integrity/platform_certs/ | UEFI db/MOK에서 키 로드 |
security/lockdown/ | Lockdown LSM |
certs/ | 빌드 시 인증서 처리, system_keyring |
crypto/asymmetric_keys/ | 비대칭키, PKCS#7, X.509 파서 |
kernel/module/signing.c | 모듈 서명 검증 |
drivers/firmware/efi/ | UEFI 런타임, efivars, Secure Boot 감지 |
include/linux/verification.h | 서명 검증 API |
플랫폼 키링 로드
/* security/integrity/platform_certs/load_uefi.c
*
* Secure Boot db에서 인증서를 로드하여 .platform_keyring에 추가
* 커널 초기화 시 자동으로 호출됨
*/
static int __init load_uefi_certs(void)
{
efi_guid_t secure_var = EFI_IMAGE_SECURITY_DATABASE_GUID;
efi_guid_t mok_var = EFI_SHIM_LOCK_GUID;
void *db = NULL, *dbx = NULL, *mok = NULL;
unsigned long dbsize, dbxsize, moksize;
/* UEFI db 변수에서 인증서 로드 → .platform_keyring */
db = get_cert_list(L"db", &secure_var, &dbsize);
if (db) {
add_to_platform_keyring("UEFI:db", db, dbsize);
kfree(db);
}
/* UEFI dbx 변수에서 폐기 목록 로드 → .blacklist_keyring */
dbx = get_cert_list(L"dbx", &secure_var, &dbxsize);
if (dbx) {
add_to_blacklist_keyring("UEFI:dbx", dbx, dbxsize);
kfree(dbx);
}
/* Shim MOK 변수에서 인증서 로드 → .platform_keyring */
mok = get_cert_list(L"MokListRT", &mok_var, &moksize);
if (mok) {
add_to_platform_keyring("UEFI:MokListRT", mok, moksize);
kfree(mok);
}
return 0;
}
late_initcall(load_uefi_certs);
키링 계층 구조
/*
* Linux 커널 키링 계층:
*
* .builtin_trusted_keys ← 커널 빌드 시 내장 (CONFIG_SYSTEM_TRUSTED_KEYS)
* │ 자기 서명 인증서 또는 CA 인증서
* │
* ├── .secondary_trusted_keys ← 런타임 추가 가능 (builtin으로 서명된 키만)
* │ ├── MOK 인증서 ← Shim에서 전달
* │ └── IMA 키 ← IMA 정책에 의해 추가
* │
* ├── .platform_keyring ← UEFI db + MokListRT에서 자동 로드
* │ 모듈/kexec 검증에 사용
* │
* ├── .blacklist_keyring ← UEFI dbx에서 자동 로드
* │ 차단할 키/해시
* │
* └── .ima_keyring ← IMA appraise용 공개키
* (CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY)
*/
# 키링 내용 확인
$ keyctl show %:.builtin_trusted_keys
Keyring
123456 ---lswrv 0 0 asymmetric: Build time autogenerated kernel key: ab:cd:...
$ keyctl show %:.platform_keyring
Keyring
234567 ---lswrv 0 0 asymmetric: Microsoft Corporation UEFI CA 2011: ...
345678 ---lswrv 0 0 asymmetric: Canonical Ltd. Secure Boot Signing: ...
$ keyctl show %:.blacklist_keyring
Keyring
456789 ---lswrv 0 0 blacklist: tbs:abc123...
13. 트러블슈팅
일반적인 문제와 해결
| 증상 | 원인 | 해결 |
|---|---|---|
| 부팅 시 "Security Violation" | 서명되지 않은 부트로더/커널 | db에 등록된 키로 서명, 또는 MOK 등록 |
modprobe: ERROR: could not insert module: Required key not available | 모듈 서명 누락 또는 키 불일치 | sign-file로 모듈 서명, 또는 MOK에 키 등록 |
Lockdown: debugfs: restricted | Lockdown integrity 모드 활성 | lockdown=none 커맨드라인 (디버깅 시) |
| DKMS 모듈 로드 실패 | 자동 서명 미설정 | DKMS MOK 키 생성 + mokutil --import |
kexec: Permission denied | CONFIG_KEXEC_SIG_FORCE + 미서명 커널 | 서명된 커널 사용 또는 kexec -s 옵션 |
| Setup Mode에서 PK 등록 불가 | 일부 펌웨어에서 Setup Mode 진입 방식 상이 | BIOS 설정에서 "Clear Secure Boot keys" 후 재시도 |
| SBAT 정책에 의한 GRUB 거부 | SbatLevel이 GRUB의 세대번호보다 높음 | 최신 GRUB 패키지 업데이트 |
| IMA appraise 실패로 파일 실행 불가 | security.ima xattr 누락/불일치 | evmctl ima_sign으로 재서명 |
디버깅 명령
# ============ Secure Boot 상태 확인 ============
# Secure Boot 활성 여부
$ mokutil --sb-state
SecureBoot enabled
# UEFI 변수 직접 확인
$ od -An -tx1 /sys/firmware/efi/efivars/SecureBoot-*
06 00 00 00 01
# ^^ 01 = enabled, 00 = disabled
# Setup Mode 확인
$ od -An -tx1 /sys/firmware/efi/efivars/SetupMode-*
06 00 00 00 00
# ^^ 00 = User Mode, 01 = Setup Mode
# ============ 키/인증서 확인 ============
# UEFI 보안 변수 목록
$ efi-readvar
Variable PK, length 862
PK: List 0, type X509
Signature 0, size 834, owner ...
Subject: CN=...
Variable KEK, length 1532
...
# 등록된 MOK 확인
$ mokutil --list-enrolled
# SBAT 폐기 목록
$ mokutil --list-sbat-revocations
# ============ 커널 키링 ============
$ keyctl show %:.builtin_trusted_keys
$ keyctl show %:.secondary_trusted_keys
$ keyctl show %:.platform_keyring
$ keyctl show %:.blacklist_keyring
# ============ 부팅 로그 ============
$ dmesg | grep -iE "secure.boot|lockdown|integrity|efi.*cert|ima|evm"
secureboot: Secure boot enabled
Lockdown: Kernel is locked down from EFI Secure Boot mode
integrity: Platform Keyring initialized
integrity: Loading X.509 certificate: UEFI:db
ima: policy update completed
# ============ 모듈 서명 ============
# 특정 모듈의 서명 정보
$ modinfo -F signer
$ modinfo -F sig_hashalgo
# 서명 없는 모듈 찾기
$ for mod in $(find /lib/modules/$(uname -r) -name "*.ko"); do
if ! modinfo -F signer $mod &>/dev/null; then
echo "Unsigned: $mod"
fi
done
14. 커널 설정 종합
# ===== Secure Boot 관련 커널 설정 종합 =====
# -- 기본 EFI 지원 --
CONFIG_EFI=y
CONFIG_EFI_STUB=y
CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE=y
# -- Lockdown LSM --
CONFIG_SECURITY_LOCKDOWN_LSM=y
CONFIG_SECURITY_LOCKDOWN_LSM_EARLY=y
CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT=y
# -- 모듈 서명 --
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y
CONFIG_MODULE_SIG_ALL=y
CONFIG_MODULE_SIG_SHA256=y
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
# -- 키링/인증서 --
CONFIG_SYSTEM_TRUSTED_KEYRING=y
CONFIG_SYSTEM_TRUSTED_KEYS="certs/signing_key.pem"
CONFIG_SECONDARY_TRUSTED_KEYRING=y
CONFIG_INTEGRITY_PLATFORM_KEYRING=y
# -- 비대칭키/서명 검증 --
CONFIG_ASYMMETRIC_KEY_TYPE=y
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
CONFIG_X509_CERTIFICATE_PARSER=y
CONFIG_PKCS7_MESSAGE_PARSER=y
CONFIG_PKCS7_TEST_KEY=y
CONFIG_SIGNED_PE_FILE_VERIFICATION=y
# -- kexec 서명 --
CONFIG_KEXEC_FILE=y
CONFIG_KEXEC_SIG=y
CONFIG_KEXEC_SIG_FORCE=y
CONFIG_KEXEC_BZIMAGE_VERIFY_SIG=y
# -- IMA/EVM --
CONFIG_INTEGRITY=y
CONFIG_INTEGRITY_SIGNATURE=y
CONFIG_IMA=y
CONFIG_IMA_MEASURE_PCR_IDX=10
CONFIG_IMA_APPRAISE=y
CONFIG_IMA_APPRAISE_MODSIG=y
CONFIG_EVM=y
# -- dm-verity --
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
CONFIG_DM_VERITY_FEC=y
# -- TPM --
CONFIG_TCG_TPM=y
CONFIG_TCG_TIS=y
CONFIG_TCG_CRB=y