콘텐츠로 이동

v0.6

SEAuditDigest CBOR 스키마 및 SE 역할 경계 정의

1. 설계 원칙

1.1. "SE에서 처리"의 명확한 경계

D'CENT Enterprise의 3-Zone 아키텍처에서 SE(Secure Element, Zone 3)는 감사 무결성 체인의 최하위 신뢰 앵커(trust anchor)로 기능한다. SE의 역할은 엄격히 제한되며, 이 경계를 명확히 정의하는 것이 본 문서의 핵심 목적이다.

SE가 수행하는 역할: | 역할 | 설명 | 업데이트 주기 | |------|------|-------------| | 해시 앵커 저장 | latest_log_hashlatest_sign_hash에 최신 해시 저장 | 동기화 시 / 서명 시 | | 서명 카운터 유지 | sign_counter 단조 증가, 롤백 불가 | 서명 수행 시마다 | | 다이제스트 서명 | digest_sig로 SEAuditDigest 전체를 SE 개인키로 서명 | 모든 필드 변경 시 | | 정책 해시 저장 | policy_hash에 현재 적용 정책의 해시 저장 | 정책 변경 시 |

SE가 수행하지 않는 역할: | 제외 항목 | 이유 | 대안 (담당 Zone) | |----------|------|----------------| | 상세 감사 로그 저장 | NVM 용량 제한 (16KB 전체), 구조화 데이터 부적합 | Zone 2 (오프라인 앱 로컬 스토리지) | | 로그 검색/필터링 | SE 프로세서의 연산 성능 부족 | Zone 1 (대시보드 DB 쿼리) | | 이벤트 분류/분석 | 복잡한 로직 실행 불가 | Zone 1 (대시보드 분석 엔진) | | 보고서 생성 | 출력 포맷 변환, 템플릿 처리 불가 | Zone 1 (대시보드 보고서 엔진) | | 시간 관리 | SE 내부 RTC(Real-Time Clock) 없음 | Zone 2 (오프라인 앱이 시간 제공) |

1.2. 설계 근거

EAL5+ SE 자원 제약: - NVM 저장소: 총 16KB 중 ~3.7KB 사용(v0.5 기준), SEAuditDigest에 128B 추가 - APDU 전송: 단일 명령/응답 최대 256B, 128B 다이제스트는 1회 전송으로 처리 가능 - 연산 속도: ECDSA P-256 서명 ~150ms, SHA-256 해시 ~5ms

128 bytes 크기 결정 근거: 1. SE NVM 예산 대비 최소 오버헤드 (전체 대비 0.8%) 2. APDU 1회 전송 가능 (256B 제한 내) 3. 해시 앵커 + 카운터 + 정책 추적에 필요한 최소 정보 포함 4. 3 bytes 예약 공간으로 향후 확장 가능 (Phase 31 규제 태그 등)

규제 근거: | 규제 | 요건 | SEAuditDigest 대응 | |------|------|-------------------| | REG-KR-14 | 변조 불가 감사 로그 | SE NVM 저장 + digest_sig 서명 = 하드웨어 레벨 변조 방지 | | CORE-04 | 3계층 무결성 체인 | SEAuditDigest가 Layer 1(최하위 앵커) 역할 | | CORE-09 | 정책 변경 이력 관리 | policy_hash로 정책 상태 추적 |


2. SEAuditDigest CBOR 스키마 (128 bytes 고정)

2.1. CDDL 정의

; ====================================================================
; D'CENT Enterprise SEAuditDigest Schema
; CBOR (RFC 8949) encoded, 128 bytes fixed size
; SE NVM에 저장되는 감사 무결성 앵커
; Phase: 30-audit-architecture
; ====================================================================

SEAuditDigest = {
    version:          uint .size 1,        ; 스키마 버전 (1 byte)
    sign_counter:     uint .size 4,        ; 단조 증가 서명 카운터 (4 bytes)
    latest_log_hash:  bstr .size 32,       ; Zone 2 마지막 동기화 로그 배치의 SHA-256 (32 bytes)
    latest_sign_hash: bstr .size 32,       ; 마지막 서명 트랜잭션 해시 (32 bytes)
    policy_hash:      bstr .size 32,       ; 현재 적용 정책의 SHA-256 해시 (32 bytes)
    timestamp:        uint .size 4,        ; 마지막 업데이트 epoch seconds (4 bytes)
    digest_sig:       bstr .size 20,       ; SE audit_key로 서명한 다이제스트 (20 bytes)
    reserved:         bstr .size 3,        ; 향후 확장 예약 (3 bytes)
}
; Total: 1 + 4 + 32 + 32 + 32 + 4 + 20 + 3 = 128 bytes

2.2. 바이트 레이아웃

Offset  Size  Field              Description
------  ----  -----------------  ------------------------------------------
0x00    1     version            스키마 버전 (초기값: 0x01)
0x01    4     sign_counter       서명 카운터 (big-endian uint32)
0x05    32    latest_log_hash    마지막 동기화 로그 배치 해시
0x25    32    latest_sign_hash   마지막 서명 트랜잭션 해시
0x45    32    policy_hash        현재 정책 해시
0x65    4     timestamp          마지막 업데이트 시간 (epoch seconds)
0x69    20    digest_sig         ECDSA P-256 서명의 truncated hash
0x7D    3     reserved           예약 (0x00 * 3)
------  ----  -----------------  ------------------------------------------
Total:  128 bytes

2.3. 초기 상태 (Factory Default)

SEAuditDigest (factory) = {
    version:          1,
    sign_counter:     0,
    latest_log_hash:  0x00 * 32,          ; 동기화 이력 없음
    latest_sign_hash: 0x00 * 32,          ; 서명 이력 없음
    policy_hash:      0x00 * 32,          ; 정책 미설정
    timestamp:        0,                   ; 미갱신
    digest_sig:       0x00 * 20,          ; 미서명
    reserved:         0x00 * 3,
}

3. 각 필드 상세 설명

3.1. version (1 byte)

  • 목적: 향후 SEAuditDigest 스키마 마이그레이션 지원
  • 초기값: 0x01 (Version 1)
  • 갱신 조건: 펌웨어 업데이트로 스키마 구조 변경 시
  • 호환성 규칙:
  • 오프라인 앱은 version 필드를 읽어 파싱 방법 결정
  • 알 수 없는 version은 거부하고 펌웨어 업데이트 권고
  • version 변경 시 reserved 영역을 재할당할 수 있음

3.2. sign_counter (4 bytes)

  • 목적: 서명 수행 횟수의 변조 불가 추적
  • 범위: 0 ~ 4,294,967,295 (uint32, ~43억 서명)
  • 갱신 조건: 매 서명(TX_SIGN) 수행 시 +1
  • 보안 속성:
  • 단조 증가(monotonically increasing): 감소 불가, 롤백 불가
  • SE NVM에 직접 기록되므로 소프트웨어 수준 변조 불가
  • 오프라인 앱이 이전 값과 비교하여 연속성 검증
  • 활용:
  • 오프라인 앱: 현재 sign_counter - 이전 sign_counter = 기간 내 서명 횟수 검증
  • 대시보드: 동기화된 TX_SIGN 레코드 수와 카운터 증분 일치 확인
  • Proof of Cold Storage: 콜드 환경 서명 건수 증명 (Plan 02)
  • 오버플로우 대응: uint32 최대값 도달 시 SE가 서명 거부, 새 키 생성 필요 (실무상 도달 불가)

3.3. latest_log_hash (32 bytes)

  • 목적: Zone 2 해시 체인의 앵커 포인트
  • 내용: 오프라인 앱이 AuditSyncPayload 생성 시 제출한 배치 로그의 SHA-256 해시
  • 갱신 조건: 오프라인 앱이 UPDATE_AUDIT_DIGEST APDU로 갱신 요청 시
  • 검증 흐름:
  • 오프라인 앱이 AuditSyncPayload 조립 완료
  • 배치 전체의 SHA-256 해시 계산
  • SE에 UPDATE_AUDIT_DIGEST(latest_log_hash = batch_hash) 전송
  • SE가 해시 저장 후 digest_sig 재계산
  • 대시보드가 AuditSyncPayload 수신 시 se_digest.latest_log_hash와 수신 배치 해시 비교
  • 공격 벡터 차단:
  • 오프라인 앱이 로그를 변조하면 → 배치 해시가 변경됨 → SE의 latest_log_hash와 불일치 → 대시보드에서 감지
  • SE NVM에 저장된 해시를 변조하면 → digest_sig 검증 실패 → 변조 감지

3.4. latest_sign_hash (32 bytes)

  • 목적: 마지막 서명 트랜잭션의 암호학적 증거
  • 내용: SE가 서명한 트랜잭션 데이터의 SHA-256 해시
  • 갱신 조건: 매 TX_SIGN 수행 시 자동 갱신 (SE 펌웨어 내부)
  • 활용:
  • 오프라인 앱이 마지막 서명 트랜잭션과 대조 검증
  • 감사인이 특정 시점의 마지막 서명 상태 확인
  • Proof of Cold Storage에서 콜드 서명 증명의 기초 데이터

3.5. policy_hash (32 bytes)

  • 목적: 현재 SE에 적용된 정책의 상태 추적
  • 내용: SE에 로드된 정책 번들의 SHA-256 해시
  • 갱신 조건: 정책 업데이트(PolicyUpdateBundle, Phase 31) 적용 시
  • 활용:
  • 오프라인 앱이 정책 버전 일치 확인
  • 대시보드가 "SE에 적용된 정책"과 "대시보드의 최신 정책" 일치 여부 검증
  • 임의 시점의 정책 상태를 감사 증적으로 증명
  • Phase 31 연결: PolicyUpdateBundle의 해시가 이 필드에 저장됨

3.6. timestamp (4 bytes)

  • 목적: SEAuditDigest의 마지막 갱신 시점 기록
  • 범위: epoch seconds (uint32, ~2106년까지)
  • 중요 제약: SE 내부에 RTC(Real-Time Clock)가 없음
  • 오프라인 앱이 UPDATE_AUDIT_DIGEST 시 현재 시간을 함께 전달
  • SE는 전달받은 시간이 기존 timestamp 이상인 경우에만 수용 (시간 역행 방지)
  • 따라서 timestamp의 정밀도는 "오프라인 앱이 제공한 시간"에 의존
  • 시간 정합성 검증:
  • 대시보드: se_digest.timestamp와 AuditSyncPayload 수신 시간 간 합리적 차이 확인
  • 허용 범위: |se_timestamp - sync_receive_time| < 24시간 (에어갭 지연 허용)

3.7. digest_sig (20 bytes)

  • 목적: SEAuditDigest 전체의 무결성 서명
  • 알고리즘: ECDSA P-256 서명의 truncated hash
  • SE의 audit_key(전용 P-256 키 쌍)로 서명
  • 전체 ECDSA 서명(64B)에서 SHA-256 해시를 계산한 후 앞 20 bytes 추출
  • 20 bytes = 160-bit 보안 수준, SEAuditDigest 무결성 검증에 충분
  • Truncation 근거:
  • 128B 고정 크기 제약 내에서 64B 서명은 공간 과다
  • 160-bit 해시는 충돌 저항 2^80, 목적(무결성 검증)에 충분
  • 전체 서명이 필요한 경우 READ_AUDIT_DIGEST_FULL 확장 APDU로 대응 가능
  • 서명 대상: version || sign_counter || latest_log_hash || latest_sign_hash || policy_hash || timestamp (105 bytes)
  • 갱신 조건: 모든 필드 변경 시 자동 재계산 (SE 내부)

3.8. reserved (3 bytes)

  • 목적: 향후 확장 예약 공간
  • 초기값: 0x00 * 3
  • 예상 활용 (Phase 31+):
  • 규제 태그 비트맵 (어떤 규제 관할 정책이 활성화되어 있는지)
  • 긴급 플래그 (보안 이벤트 감지 시)
  • 다이제스트 체인 시퀀스 번호
  • 제약: 128B 고정 크기를 초과할 수 없으므로, 확장 시 다른 필드 최적화와 병행

4. SEAuditDigest 업데이트 흐름

4.1. 서명 시 (TX_SIGN)

1. 오프라인 앱 -> SE: SIGN_TRANSACTION(tx_data)
2. SE 내부 처리:
   a. 트랜잭션 서명 수행 (기존 흐름)
   b. sign_counter++
   c. latest_sign_hash = SHA-256(tx_data)
   d. timestamp = 오프라인 앱 제공 시간
   e. digest_sig = Truncate20(ECDSA_P256(audit_key, digest_content))
3. SE -> 오프라인 앱: 서명 결과 + 갱신된 sign_counter

4.2. 동기화 시 (AuditSyncPayload 생성 전)

1. 오프라인 앱: AuditSyncPayload 조립
   a. 마지막 동기화 이후 축적된 AuditRecord 수집
   b. 배치 전체의 SHA-256 해시 계산 (batch_hash)
2. 오프라인 앱 -> SE: UPDATE_AUDIT_DIGEST(latest_log_hash = batch_hash, timestamp = now)
3. SE 내부 처리:
   a. latest_log_hash = batch_hash
   b. timestamp = max(기존 timestamp, 제공 timestamp)  ; 시간 역행 방지
   c. digest_sig = Truncate20(ECDSA_P256(audit_key, digest_content))
4. SE -> 오프라인 앱: ACK + 갱신된 SEAuditDigest
5. 오프라인 앱: AuditSyncPayload.se_digest에 갱신된 다이제스트 포함

4.3. 정책 변경 시 (PolicyUpdateBundle 적용)

1. 오프라인 앱 -> SE: APPLY_POLICY(policy_bundle)  ; Phase 31에서 상세 설계
2. SE 내부 처리:
   a. policy_bundle 검증 (쿼럼 서명 확인)
   b. 정책 적용
   c. policy_hash = SHA-256(policy_bundle)
   d. timestamp = 오프라인 앱 제공 시간
   e. digest_sig = Truncate20(ECDSA_P256(audit_key, digest_content))
3. SE -> 오프라인 앱: 정책 적용 결과 + 갱신된 SEAuditDigest

5. 무결성 검증 방법

5.1. 오프라인 앱 검증 (실시간)

1. SE에서 READ_AUDIT_DIGEST 수행 -> 128B 수신
2. digest_sig 검증:
   a. SE의 audit_key 공개키로 서명 검증
   b. 서명 대상 = version || sign_counter || latest_log_hash ||
                   latest_sign_hash || policy_hash || timestamp (105B)
   c. 검증 실패 시: SECURITY_EVENT(sec-tampering-detected) 생성
3. sign_counter 연속성 확인:
   a. 이전에 읽은 sign_counter 값과 비교
   b. 차이 = 그 사이 수행된 서명 횟수
   c. 기대값과 불일치 시: SECURITY_EVENT(sec-counter-mismatch) 생성
4. latest_log_hash 일치 확인:
   a. 마지막으로 SE에 제출한 batch_hash와 비교
   b. 불일치 시: 다른 앱이 SE를 업데이트했거나, SE 변조 의심

5.2. 대시보드 검증 (동기화 수신 시)

1. AuditSyncPayload 수신
2. 포함된 se_digest 검증:
   a. digest_sig 검증 (SE audit_key 공개키 사용)
   b. se_digest.latest_log_hash == SHA-256(수신 records 배치) 확인
   c. 불일치 시: 오프라인 앱 변조 또는 전송 중 변조 의심
3. sign_counter 누적 확인:
   a. 이전 동기화의 sign_counter와 비교
   b. 증분 = 기간 내 서명 횟수
   c. 수신된 TX_SIGN 레코드 수와 일치 확인
4. timestamp 정합성:
   a. se_digest.timestamp와 AuditSyncPayload 수신 시간 비교
   b. 합리적 범위(24시간) 초과 시 경고

5.3. 감사인 검증 (임의 시점 스냅샷)

1. 감사인이 감사 대상 시점 결정
2. SE에서 READ_AUDIT_DIGEST -> 현재 SEAuditDigest 스냅샷 획득
3. 대시보드에서 해당 시점의 마지막 AuditSyncPayload 조회
4. 교차 검증:
   a. SE latest_log_hash == 대시보드 기록의 마지막 동기화 배치 해시
   b. SE sign_counter >= 대시보드 기록의 누적 TX_SIGN 수
   c. SE policy_hash == 대시보드 기록의 정책 해시
5. 해시 체인 구간 검증:
   a. 감사 대상 기간의 AuditRecord 해시 체인 순회
   b. 각 레코드의 prev_hash 일치 확인
   c. 마지막 레코드의 해시 == SE latest_log_hash (또는 해당 시점의 스냅샷)
6. 검증 결과: 통과 -> "해당 기간 감사 증적 무결성 확인"
   실패 -> 변조 구간 특정 및 보고

6. SE 메모리 레이아웃 업데이트

6.1. 메모리 예산 현황

SE NVM 메모리 레이아웃 (v0.6 기준)

총 NVM: 16,384 bytes (16 KB)

기존 사용 (v0.5):
  키 저장소 (마스터 키, 유도 키 등):  ~2,048 bytes
  정책 규칙 테이블:                    ~512 bytes
  RBAC 역할 매핑:                     ~256 bytes
  MuSig2 세션 데이터:                 ~384 bytes
  인증서/메타데이터:                   ~512 bytes
  ─────────────────────────────────────────────
  v0.5 합계:                          ~3,712 bytes (~3.7 KB)

v0.6 추가:
  SEAuditDigest:                       128 bytes
  sign_counter NVM 미러링:               4 bytes  (*)
  audit_key 슬롯 인덱스:                 4 bytes
  ─────────────────────────────────────────────
  v0.6 추가 합계:                       136 bytes

v0.6 총 사용:                         ~3,848 bytes (~3.84 KB)
여유 공간:                           ~12,536 bytes (~12.16 KB)

(*) sign_counter는 SEAuditDigest 내에 포함되어 있으나,
    전원 차단 시 데이터 손실 방지를 위해 NVM 별도 영역에
    미러링(redundant copy) 권장. Wear leveling 적용.

6.2. Phase 31+ 확장 여지

예상 확장 크기 Phase 출처
규제 태그 비트맵 ~32 bytes Phase 31 SE 정책 엔진 규제 확장
PolicyUpdateBundle 캐시 ~256 bytes Phase 31 정책 버전 관리
추가 키 슬롯 ~128 bytes 후속 감사 키, 인증 키 추가
확장 후 예상 사용 ~4.3 KB - 16 KB 대비 26%

12 KB 이상의 여유 공간이 확보되어 있으므로 향후 확장에 충분하다.


7. APDU 커맨드 명세

7.1. UPDATE_AUDIT_DIGEST

오프라인 앱이 SE에 latest_log_hash 또는 policy_hash를 갱신하는 커맨드.

Command APDU:
  CLA: 0x80
  INS: 0xA0           ; AUDIT 클래스
  P1:  0x01           ; UPDATE 서브커맨드
  P2:  <update_flags> ; 어떤 필드를 갱신할지 비트 플래그
       0x01: latest_log_hash 갱신
       0x02: policy_hash 갱신
       0x03: 둘 다 갱신
  Lc:  <data length>
  Data: <갱신할 해시 값(32B)> + <timestamp(4B)>
  Le:  0x80 (128 bytes 응답 요청)

Response APDU:
  Data: 갱신된 SEAuditDigest 전체 (128 bytes)
  SW1-SW2:
    0x9000: 성공
    0x6982: 인증 필요 (PIN/서명 세션 미인증)
    0x6A80: 잘못된 데이터 (해시 크기 불일치 등)
    0x6985: 시간 역행 거부 (제공 timestamp < 기존 timestamp)

접근 제어: 기존 PIN/서명 세션 인증 완료 후에만 실행 가능. 비인증 상태에서 호출 시 0x6982 반환.

7.2. READ_AUDIT_DIGEST

SE에서 현재 SEAuditDigest를 읽는 커맨드.

Command APDU:
  CLA: 0x80
  INS: 0xA0           ; AUDIT 클래스
  P1:  0x02           ; READ 서브커맨드
  P2:  0x00           ; 전체 다이제스트 읽기
  Lc:  0x00
  Le:  0x80 (128 bytes)

Response APDU:
  Data: SEAuditDigest 전체 (128 bytes)
  SW1-SW2:
    0x9000: 성공
    0x6982: 인증 필요

접근 제어: PIN 인증 후 접근 가능. 서명 세션 중에도 읽기 가능.

7.3. APDU 보안 고려사항

항목 설계 근거
인증 요구 모든 AUDIT APDU는 PIN 인증 필수 비인가 접근 방지
timestamp 검증 제공 시간이 기존 timestamp 이상이어야 수용 시간 역행 공격 방지
sign_counter 직접 변경 불가 UPDATE_AUDIT_DIGEST로 sign_counter 변경 불가 서명 카운터 조작 방지
digest_sig 자동 재계산 모든 필드 변경 시 SE가 자동으로 재서명 수동 서명 주입 방지
NVM 원자성 필드 갱신은 원자적(atomic) — 중간 상태 없음 전원 차단 시 일관성 보장

8. Plan 02 연결점

본 문서에서 정의한 SEAuditDigest는 Plan 02의 다음 설계에 직접 연결된다:

8.1. 3계층 무결성 체인의 Layer 1

SEAuditDigest는 3계층 무결성 체인의 최하위 앵커(Layer 1)로 기능한다: - latest_log_hash: Layer 2(오프라인 앱) 해시 체인의 앵커 - digest_sig: Layer 1 자체의 무결성 증명 - Layer 2 -> Layer 3(대시보드)로의 교차 검증 시 SEAuditDigest 스냅샷이 포함됨

8.2. AuditSyncPayload 포함

AuditSyncPayload(Plan 02)의 se_digest 필드에 SEAuditDigest 128B 전체가 포함된다: - 대시보드가 수신 시 se_digest.latest_log_hash와 수신 레코드 배치 해시를 비교 - sign_counter 연속성 확인으로 누락된 서명 감지

8.3. Proof of Cold Storage 입력

  • sign_counter: 콜드 환경(에어갭 SE)에서 수행된 서명 총 횟수
  • latest_sign_hash: 마지막 콜드 서명의 암호학적 증거
  • 콜드 비율 계산: SE 관리 자산 / 전체 자산 = 100% (에어갭 구조)

Phase: 30-audit-architecture Version: 1.0 SE 메모리 기준: v0.6 (~3.84 KB / 16 KB)


관련 문서