콘텐츠로 이동

v0.0

펌웨어 업데이트 보안 메커니즘 설계서

1. Executive Summary

본 문서는 D'CENT X 엔터프라이즈 콜드월렛의 펌웨어 업데이트 보안 메커니즘을 설계한다. 에어갭 원칙을 절대적으로 유지하면서 안전한 펌웨어 업데이트를 수행하기 위한 코드 서명, 관리자 쿼럼 승인, 에어갭 전달 프로토콜, 데이터 보존, 롤백 방지 메커니즘을 정의한다.

핵심 원칙: - OTA(Over-The-Air) 업데이트 절대 금지 — CLAUDE.md "Out of Scope" 명시 - 코드 서명 필수 — D'CENT 서명 키로 서명된 바이너리만 SE가 수락 - 관리자 쿼럼 승인 — 엔터프라이즈 고객의 자체 통제권 보장 - 데이터 보존 — 펌웨어 업데이트 시 정책, 키, 카운터 데이터 완전 보존 - 롤백 방지 — 버전 번호 단조 증가, 다운그레이드 공격 차단


2. 펌웨어 업데이트 보안 원칙

2.1. 에어갭 유지 원칙

원칙 설명 위반 시
OTA 절대 금지 WiFi, Bluetooth, 셀룰러, USB 데이터 연결을 통한 펌웨어 전달 불가 공급망 공격, 원격 백도어 설치 벡터
에어갭 채널만 허용 QR 코드(Animated QR, 대시보드→앱), USB-C(앱→콜드월렛), MicroSD(폴백)
물리 버튼 확인 필수 모든 펌웨어 설치에 사용자 물리 버튼 승인 필요 자동 업데이트 방지
SE 독립 검증 SE가 독립적으로 서명을 검증 — 오프라인 앱 신뢰하지 않음 MITM 방어

2.2. 이중 서명 체계

D'CENT X 엔터프라이즈에서는 이중 서명 체계를 채택한다:

이중 서명 = D'CENT 코드 서명 + 엔터프라이즈 Admin 쿼럼 서명

목적:
  - D'CENT 서명: 펌웨어 바이너리의 진위 보장 (공급망 보안)
  - Admin 쿼럼 서명: 기업의 자체 업데이트 통제 (자치권 보장)

어느 한 쪽만으로는 펌웨어 설치 불가.

3. 펌웨어 바이너리 서명 메커니즘

3.1. 코드 서명 키 관리

D'CENT 펌웨어 서명 키:

항목 사양 비고
알고리즘 ECDSA secp256k1 (또는 Ed25519) SE에서 검증 가능한 알고리즘
키 보호 HSM(FIPS 140-3 Level 3) 내부 생성/저장 HSM 외부 추출 불가
키 교체 연 1회 계획 교체 + 긴급 교체 절차 구 키 유효 기간 90일
공개키 배포 SE 내부에 사전 저장 (D'CENT 공개키) 제조 시 주입
백업 Shamir's Secret Sharing (3-of-5) 금고 보관 지리적 분산

키 교체 절차:

키 교체 워크플로우:
  [1] 신규 키 쌍을 HSM 내부에서 생성
  [2] 구 키로 "키 교체 인증서" 서명:
      KeyRotationCert {
        old_pubkey: bytes(33)
        new_pubkey: bytes(33)
        effective_version: uint32  // 이 버전부터 신규 키 적용
        transition_period: uint32  // 구 키 유효 기간 (초)
        old_key_signature: bytes(64)
      }
  [3] 키 교체 인증서를 펌웨어 업데이트에 포함
  [4] SE가 구 키로 인증서 검증 → 신규 키 저장
  [5] transition_period 동안 양쪽 키 모두 수락
  [6] transition_period 경과 후 구 키 무효화

3.2. 바이너리 서명 구조

SignedFirmwareBinary {
  header: FirmwareHeader {
    magic: bytes(4)              // "DCFW" (0x44434657)
    header_version: uint8        // 헤더 구조 버전 (0x01)
    firmware_version: uint32     // 단조 증가 버전 번호
    target_model: uint16         // 대상 하드웨어 모델 ID
    build_timestamp: uint32      // 빌드 타임스탬프 (참조용)
    binary_size: uint32          // 펌웨어 바이너리 크기 (bytes)
    flags: uint16                // 플래그 (SE 전용, MCU 전용, 전체 등)
    min_hw_version: uint16       // 최소 호환 하드웨어 버전
    reserved: bytes(8)           // 예약 영역
  }                              // 합계: 32 bytes

  code_hash: bytes(32)           // SHA-256(firmware_binary)

  dcent_signature: {
    pubkey_id: uint8             // D'CENT 공개키 인덱스 (키 교체 지원)
    signature: bytes(64)         // ECDSA(header || code_hash, D'CENT 서명 키)
  }                              // 65 bytes

  admin_approval: {              // 엔터프라이즈 Admin 쿼럼 서명
    quorum_threshold: uint8      // 필요 서명 수 (M)
    signature_count: uint8       // 실제 서명 수
    signatures: [{
      admin_pubkey: bytes(33)    // Admin 공개키
      signature: bytes(64)       // ECDSA(header || code_hash, Admin 개인키)
    }]                           // 97 bytes x M
  }

  firmware_binary: bytes         // 실제 펌웨어 바이너리
}

3.3. SE 검증 프로세스

펌웨어 바이너리 검증 흐름:

[1] 헤더 파싱
    ├─ magic == "DCFW" 확인
    ├─ header_version 지원 확인
    └─ target_model == 현재 디바이스 모델 확인
    │
    ▼
[2] 버전 검증
    ├─ firmware_version > SE 현재 버전 (롤백 방지)
    └─ firmware_version == SE 현재 버전 + 1 (연속 버전 권장)
    │   └─ 비연속 시: 경고 표시하나 설치 허용
    │
    ▼
[3] 코드 해시 검증
    ├─ SHA-256(firmware_binary) 계산
    └─ code_hash 필드와 대조
    │   └─ 불일치 → FIRMWARE_INTEGRITY_FAILED (에러)
    │
    ▼
[4] D'CENT 코드 서명 검증
    ├─ SE 내부 저장 D'CENT 공개키 로드 (pubkey_id 참조)
    └─ ECDSA verify(header || code_hash, dcent_signature)
    │   └─ 실패 → FIRMWARE_SIGNATURE_INVALID (에러)
    │
    ▼
[5] Admin 쿼럼 서명 검증
    ├─ 각 admin_pubkey가 SE 저장 Admin 목록에 포함 확인
    ├─ 각 서명의 ECDSA 검증
    └─ 유효 서명 수 >= quorum_threshold
    │   └─ 미달 → FIRMWARE_ADMIN_QUORUM_FAILED (에러)
    │
    ▼
[6] 물리 버튼 확인
    ├─ "펌웨어 업데이트: v[현재] → v[신규]"
    ├─ "크기: [N] KB"
    └─ 물리 버튼 2회 확인 (업데이트 인지 + 최종 승인)
    │
    ▼
[7] 데이터 영역 무결성 스냅샷 (업데이트 전)
    └─ data_hash_before = SHA-256(전체 데이터 영역)
    │
    ▼
[8] 펌웨어 설치 진행
    │
    ▼
[9] 데이터 영역 무결성 검증 (업데이트 후)
    ├─ data_hash_after = SHA-256(전체 데이터 영역)
    └─ data_hash_before == data_hash_after ?
        ├─ 일치 → 업데이트 성공
        └─ 불일치 → 롤백 + FIRMWARE_DATA_CORRUPTION (에러)

4. 에어갭 펌웨어 전달 프로토콜

4.1. QR 채널 (Animated QR)

Animated QR(Fountain 코드)를 통한 펌웨어 바이너리 분할 전달:

항목 사양
UR 타입 dcent-firmware-update (CBOR 태그 45040)
프레임당 데이터 ~500 bytes (QR Version 12, Level L)
Fountain 코드 LT 코드, 원본 프래그먼트의 2-3배 여분

전송 시간 추정:

바이너리 크기 프레임 수 전송 시간 (100ms/frame) UX 평가
50KB ~200 프레임 ~20초 수용 가능
100KB ~400 프레임 ~40초 인내 필요
200KB ~800 프레임 ~80초 경계
500KB ~2000 프레임 ~200초 (3분+) USB-C/MicroSD 권장

4.2. USB-C 채널

USB-C 케이블을 통한 펌웨어 바이너리 전달 (오프라인 앱 → 콜드월렛):

항목 사양
연결 방식 USB-C 케이블 (오프라인 앱 디바이스 ↔ D'CENT X)
전송 속도 USB 2.0: 480 Mbps
50KB 전송 < 1초
200KB 전송 < 1초
안정성 유선 연결로 매우 안정적

USB-C 펌웨어 업데이트 프로토콜:

단계 설명
1. 헤더 전송 FirmwareHeader(32B) 전송 → SE에서 버전/모델 사전 검증
2. 바이너리 전송 서명된 펌웨어 바이너리 청크 단위 전송
3. 완료 확인 전체 바이너리 수신 완료 → 무결성 검증 진행

4.3. MicroSD 채널 (폴백)

물리적 MicroSD 카드를 통한 펌웨어 파일 전달:

항목 사양
파일 시스템 FAT32
파일 경로 /DCENT/firmware/dcent_fw_v[VERSION].bin
파일 형식 SignedFirmwareBinary 전체 (헤더 + 서명 + 바이너리)
장점 대용량 전송 가장 빠름, 단순
단점 물리 포트 공격 면적 존재 (USB/SD 슬롯)
보안 대책 파일 읽기 전용, 파일 시스템 파싱 최소화, 서명 검증 후 진행

4.4. 채널별 비교 매트릭스

기준 QR (Animated) USB-C MicroSD
보안성 최고 (시각적, 물리 연결 없음) 높음 (오프라인 전용 디바이스 연결) 중간 (물리 포트)
속도 (50KB) ~20초 < 1초 ~1초
속도 (200KB) ~80초 < 1초 ~2초
UX 카메라 위치 유지 필요 USB-C 케이블 연결 카드 삽입
하드웨어 요구 카메라 + 화면 USB-C 포트 SD 슬롯
권장 용량 < 100KB 무제한 무제한
에어갭 보장 완전 완전 (오프라인 앱 경유) 완전 (데이터만)

권장 전략: 1. 기본: USB-C (속도와 안정성의 최적 균형, 오프라인 앱 경유) 2. 고보안: QR (완전한 시각적 검증, 대시보드→앱 구간) 3. 폴백: MicroSD (USB-C/QR 불가 시)

4.5. 무결성 검증

모든 채널에서 수신 완료 후:

수신 후 무결성 검증:
  1. 전체 바이너리 수신 완료 확인 (binary_size 대조)
  2. SHA-256(수신된 firmware_binary) 재계산
  3. 헤더의 code_hash와 대조
  4. 불일치 → "펌웨어 파일 손상" 경고 + 재전송 요청
  5. 일치 → 서명 검증 진행 (섹션 3.3)

5. 관리자 쿼럼 승인 워크플로우

5.1. 업데이트 제안

펌웨어 업데이트 제안 워크플로우:

[1] D'CENT이 신규 펌웨어 버전 릴리스
    ├─ 서명된 바이너리 + 릴리스 노트 + 변경 로그
    └─ 대시보드에 업데이트 가용 알림

[2] Admin이 대시보드에서 업데이트 검토
    ├─ 변경 내용 확인
    ├─ 보안 취약점 패치 여부 확인
    └─ 업데이트 제안 생성

[3] 업데이트 제안 = FirmwareUpdateProposal
    ├─ firmware_version: 대상 버전
    ├─ code_hash: SHA-256 해시
    ├─ release_notes: 변경 내용 요약
    ├─ urgency: normal / high / critical
    └─ proposer: Admin ID + 서명

5.2. 쿼럼 서명 수집

Admin 쿼럼 서명 수집:

[1] 제안 알림 → 모든 Admin에게 전달
[2] 각 Admin이 자신의 D'CENT X 콜드월렛으로:
    a. 업데이트 제안 내용 확인 (버전, 해시, 변경 내용)
    b. 물리 버튼으로 승인 서명 생성
    c. 서명을 오프라인 앱 → 대시보드로 전달 (에어갭 경유)
[3] 최소 M-of-N (기본 3-of-5) 서명 수집
[4] 대시보드에서 승인 페이로드 조립

승인 페이로드:
  FirmwareUpdateApproval {
    firmware_version: uint32
    code_hash: bytes(32)
    admin_signatures: [{pubkey, signature}]  // M개
    quorum_threshold: uint8                  // M
    approved_timestamp: uint32               // 참조용
  }

5.3. SE 검증 및 설치

SE 측 검증:

[1] D'CENT 코드 서명 검증 (섹션 3.3 참조)
[2] Admin 쿼럼 서명 검증:
    - 각 pubkey가 SE 저장 Admin 목록에 존재 확인
    - 각 서명의 ECDSA 검증 (code_hash 기준)
    - 유효 서명 수 >= quorum_threshold 확인
[3] 물리 버튼 2회 확인:
    - 1회: "펌웨어 업데이트 v1.2.0 → v1.3.0. Admin 3명 승인됨."
    - 2회: "설치를 최종 승인합니까?"
[4] 데이터 영역 스냅샷 → 펌웨어 설치 → 데이터 영역 검증

6. 펌웨어 업데이트 시 데이터 보존 전략

6.1. 보존 대상

영역 크기 중요도 손상 시 복구 방법
개인키 (HD derived) ~1,600B 최고 Shamir's Secret Sharing 백업 복원 + 키 세레모니
정책 데이터 256B 높음 Admin 쿼럼 재설정
Merkle Root 32B 높음 대시보드에서 재생성 + Admin 쿼럼 전달
Admin 공개키 세트 512B 최고 키 세레모니 수준 절차
서명 카운터 4B 높음 0으로 리셋 시 일일 한도 리셋됨 — 보안 영향
토큰 DB 2,048B 중간 펌웨어 업데이트 시 재초기화 가능
셀렉터 DB 4,096B 중간 펌웨어 업데이트 시 재초기화 가능
MuSig2 세션 132B 낮음 업데이트 시 세션 폐기 (재시작)
WYSIWYS 잠금 카운터 8B 낮음 0으로 리셋 (잠금 해제)
합계 ~8,688B

6.2. 보존 메커니즘

SE 메모리 레이아웃 (논리적 분리):

┌──────────────────────────────────────┐
│           SE Flash/EEPROM             │
│                                       │
│  ┌───────────────────────────────┐   │
│  │     Firmware Code Area         │   │  ← 업데이트 대상
│  │     (펌웨어 바이너리)           │   │
│  │                                │   │
│  ├───────────────────────────────┤   │
│  │     Data Preservation Area     │   │  ← 업데이트 시 보존
│  │     (키, 정책, 카운터)          │   │
│  │                                │   │
│  │     보존 해시: SHA-256(전체)    │   │
│  ├───────────────────────────────┤   │
│  │     Recovery Partition         │   │  ← 복구 전용
│  │     (부트로더 + 최소 펌웨어)    │   │
│  └───────────────────────────────┘   │
└──────────────────────────────────────┘

보존 프로세스:
  [1] 업데이트 전: data_hash = SHA-256(Data Preservation Area)
  [2] 펌웨어 설치: Firmware Code Area만 덮어쓰기
  [3] 업데이트 후: new_hash = SHA-256(Data Preservation Area)
  [4] 검증: data_hash == new_hash
      ├─ 일치 → 성공
      └─ 불일치 → 롤백 (Recovery Partition에서 복구)

6.3. 최악의 경우 (데이터 손상)

데이터 영역 손상 시 복구 절차:

데이터 손상 감지 후:

[1] Recovery Partition의 최소 펌웨어로 부팅
[2] 화면에 "데이터 손상 감지 — 복구 모드" 표시
[3] 복구 옵션:
    a. 정책 재설정:
       - Admin 쿼럼 서명 + 신규 정책 페이로드 → 에어갭 전달
       - 서명 카운터 리셋 → 일일 한도 리셋 (보안 경고)
    b. 키 복구:
       - Shamir's Secret Sharing 백업에서 마스터 시드 복원
       - 키 세레모니 수준의 보안 절차 요구
       - 복구 후 모든 정책 재설정 필수
    c. Admin 키 복구:
       - N-of-N 기존 Admin 서명으로 신규 Admin 키 세트 등록
       - 기존 Admin 전원 접근 불가 시: 키 세레모니 재수행
[4] 복구 완료 후 정상 모드 재부팅

7. 롤백 방지 및 다운그레이드 공격 방어

7.1. 버전 카운터

항목 사양
저장 위치 SE 내부 NV(Non-Volatile) 카운터 또는 Fuse 기반
데이터 타입 uint32 (단조 증가)
초기값 1
최대값 4,294,967,295 (약 40억 — 실질적으로 무한)
업데이트 조건 펌웨어 설치 성공 시에만 증가

7.2. 안티롤백 검증

안티롤백 로직:

SE에 저장된 현재 버전: current_fw_version (uint32)
수신된 펌웨어 버전: new_fw_version (uint32)

검증:
  if new_fw_version <= current_fw_version:
    return FIRMWARE_ROLLBACK_REJECTED
    // 이전 또는 동일 버전 설치 불가

  if new_fw_version > current_fw_version + 100:
    // 비연속 버전 경고 (선택적)
    display_warning("버전 건너뛰기 감지")
    // 설치는 허용 (Admin 승인 있으므로)

  설치 성공 후:
    current_fw_version = new_fw_version  // NV 업데이트

7.3. 브릭 방지

펌웨어 업데이트 실패 시 디바이스가 사용 불가(브릭) 상태가 되지 않도록 보호:

A/B 파티션 방식 (권장):

SE Flash 파티션:
  Partition A: 현재 실행 중인 펌웨어
  Partition B: 업데이트 대상 파티션
  Boot Selector: A 또는 B 선택

업데이트 프로세스:
  [1] 새 펌웨어를 Partition B에 쓰기
  [2] Boot Selector를 B로 변경
  [3] 리부트 → B에서 부팅 시도
  [4] 부팅 성공 → B가 새 "현재" 파티션
  [5] 부팅 실패 → 자동으로 A에서 부팅 (이전 펌웨어)

장점: 업데이트 실패 시에도 이전 펌웨어로 복구
단점: Flash 공간 2배 필요

Recovery Partition 방식 (대안):

SE Flash 파티션:
  Main Partition: 펌웨어 + 데이터
  Recovery Partition: 최소 부트로더 + 복구 기능

업데이트 프로세스:
  [1] 새 펌웨어로 Main Partition 덮어쓰기
  [2] 부팅 시 무결성 검증 (CRC32 또는 SHA-256)
  [3] 검증 실패 → Recovery Partition에서 부팅
  [4] Recovery 모드에서 펌웨어 재수신/재설치

장점: Flash 공간 절약
단점: 복구 시 펌웨어 재전송 필요

[HW-CONFIRM] D'CENT X의 MCU/SE Flash 레이아웃에 따라 A/B 파티션 또는 Recovery Partition 방식을 최종 선택한다.


8. 펌웨어 업데이트 요구사항 목록

ID 요구사항명 상세 설명 우선순위 연계 문서
FW-UPDATE-01 코드 서명 검증 D'CENT 공개키로 ECDSA 서명 검증, 키 인덱스 기반 다중 키 지원 필수 섹션 3
FW-UPDATE-02 Admin 쿼럼 서명 검증 M-of-N Admin 서명 검증 (기본 3-of-5), SE 저장 Admin 목록 대조 필수 섹션 5
FW-UPDATE-03 바이너리 무결성 검증 SHA-256(firmware_binary) 재계산 → code_hash 대조 필수 섹션 3.2
FW-UPDATE-04 버전 롤백 방지 NV 카운터 기반 단조 증가, 이전 버전 설치 거부 필수 섹션 7
FW-UPDATE-05 데이터 영역 보존 업데이트 전후 데이터 영역 SHA-256 비교, 불일치 시 롤백 필수 섹션 6
FW-UPDATE-06 물리 버튼 2회 확인 "펌웨어 업데이트" 인지 + 최종 승인 필수 섹션 3.3
FW-UPDATE-07 QR 채널 수신 Animated QR Fountain 코드 수신 + UR 디코딩 필수 섹션 4.1
FW-UPDATE-08 USB-C 채널 수신 USB-C를 통한 펌웨어 바이너리 수신 (오프라인 앱 경유) 필수 섹션 4.2
FW-UPDATE-09 MicroSD 채널 수신 FAT32 파일 읽기, 서명된 바이너리 파일 로드 높음 섹션 4.3
FW-UPDATE-10 브릭 방지 A/B 파티션 또는 Recovery Partition 기반 실패 복구 필수 섹션 7.3
FW-UPDATE-11 키 교체 인증서 처리 구 키로 서명된 키 교체 인증서 검증 → 신규 키 저장 높음 섹션 3.1
FW-UPDATE-12 데이터 손상 복구 모드 Recovery Partition 부팅, 정책/키 재설정 인터페이스 높음 섹션 6.3
FW-UPDATE-13 업데이트 진행 상태 표시 화면에 수신 진행률, 검증 단계 표시 중간 UX
FW-UPDATE-14 업데이트 로그 기록 업데이트 이력(버전, 시점, 채널, 승인 Admin) SE 로그 중간 감사 추적

본 문서는 Phase 6 Firmware Requirements의 세 번째 산출물(1/2)로, 에어갭 환경에서의 펌웨어 업데이트 보안 메커니즘을 설계한다. CLAUDE.md의 "OTA 펌웨어 업데이트 금지" 원칙을 준수하며, Phase 4 hardware-policy-engine.md 섹션 5.4의 정책 데이터 보존 전략을 구체화하였다. FW-UPDATE-01~14의 요구사항 ID 체계로 추적 가능하며, Phase 5 airgap-communication-protocol.md의 전달 채널 사양을 기반으로 한다.


관련 문서