제 2 장: 데이터 모델
본 장은 CAP 프로토콜의 핵심 데이터 구조를 정의하며, 필드명, 타입, 제약 및 기본값을 포함한다. 본 장의 필드 정의는 규범적이다 — CAP 프로토콜에 적합한 모든 구현은 MUST 본 장 정의에 따라 이러한 데이터 구조를 생성하고 파싱한다.
schema/{version}/schema.json은 본 장 데이터 구조의 형식적 보충을 제공한다. schema.json과 본 장 기술이 충돌하는 경우 schema.json을 우선한다.
2.1 데이터 타입 규약
본 사양은 다음 기본 타입을 사용하여 필드를 기술한다:
| 타입 | 설명 | 인코딩 |
|---|---|---|
string | UTF-8 문자열 | UTF-8 바이트 시퀀스 |
bytes | 바이트 시퀀스 | 원시 바이트 |
uint32 / uint64 | 부호 없는 정수 | 빅 엔디안 |
timestamp | Unix 타임스탬프(초) | uint64 |
uuid | RFC 4122 UUID v7 | 16 바이트 |
enum | 열거 값 | 문자열 리터럴 |
array<T> | T 타입 요소의 순서 집합 | 배열 |
map<K,V> | K에서 V로의 매핑 | 객체 |
필드 제약은 다음 표기법을 사용한다:
required: 필드는 MUST 출현하며, 값은 null이 아니다optional: 필드는 MAY 출현하며, 누락 시 미설정으로 간주된다unique: 필드 값은 시스템 범위 내에서 고유하다len(N..M): 문자열/바이트 길이는 N에서 M 사이(끝점 포함)regex(...): 필드 값은 MUST 지정된 정규 표현식과 일치한다
2.2 식별자
CAP 프로토콜의 핵심 식별자는 MUST 글로벌 고유성을 충족한다. 본 절은 각종 식별자의 형식과 생성 규칙을 정의한다.
2.2.1 Fay_ID
Fay_ID는 Fay 인스턴스를 고유하게 식별한다.
| 속성 | 값 |
|---|---|
| 타입 | string |
| 형식 | "fay:" + uuid_v7 |
| 길이 | 40 문자(접두사 포함) |
| 고유성 | 글로벌 고유 |
| 생성자 | 신원 관리 서브시스템(CAP 프로토콜 범위 외) |
예: fay:01927b34-7e21-7c4d-a89f-1234567890ab
2.2.2 Terminal_ID
Terminal_ID는 단말 장치를 고유하게 식별한다.
| 속성 | 값 |
|---|---|
| 타입 | string |
| 형식 | "terminal:" + uuid_v7 |
| 길이 | 45 문자(접두사 포함) |
| 고유성 | 글로벌 고유 |
| 생성자 | Registration_Authority |
2.2.3 Resource_ID
Resource_ID는 단말상의 구체적 리소스를 식별한다.
| 속성 | 값 |
|---|---|
| 타입 | string |
| 형식 | terminal_id + "/" + resource_path |
| 길이 | 최대 256 문자 |
| 고유성 | 단말 범위 내 고유 |
| 생성자 | 단말 운영체제 |
resource_path는 MUST 정규 표현식 ^[a-zA-Z0-9._\-/]+$을 충족한다.
예: terminal:01927b34-.../device/camera/front
2.2.4 Descriptor_ID
Descriptor_ID는 하나의 Authorization_Descriptor를 고유하게 식별한다.
| 속성 | 값 |
|---|---|
| 타입 | uuid |
| 형식 | UUID v7 |
| 고유성 | 글로벌 고유(모든 Descriptor_Issuer 범위 내) |
| 생성자 | Descriptor_Issuer |
폐기 목록은 Descriptor_ID를 사용하여 폐기된 자격 증명을 식별한다. Descriptor_Issuer는 MUST NOT 이미 사용된 Descriptor_ID를 재사용한다.
2.2.5 Session_ID
Session_ID는 활성 세션을 고유하게 식별한다.
| 속성 | 값 |
|---|---|
| 타입 | uuid |
| 형식 | UUID v7 |
| 고유성 | 단말 범위 내 고유 |
| 생성자 | 단말 Protocol_Engine |
| 라이프사이클 | 세션이 활성인 동안에만 유효, 세션 종료 후 ID는 재사용되지 않음 |
2.3 Authorization_Descriptor
Authorization_Descriptor는 오프라인 인가의 핵심 데이터 구조다. 하나의 Authorization_Descriptor는 두 부분으로 구성된다: 페이로드(payload) 와 서명(signature).
2.3.1 최상위 구조
AuthorizationDescriptor {
required version : uint32
required payload : DescriptorPayload
required signature : DescriptorSignature
}
| 필드 | 설명 |
|---|---|
version | 프로토콜 버전 번호, v1 구현은 MUST 1로 설정한다 |
payload | 인가 정보 페이로드(§2.3.2 참조) |
signature | payload에 대한 디지털 서명(§2.3.3 참조) |
2.3.2 DescriptorPayload
DescriptorPayload {
required descriptor_id : Descriptor_ID
required issuer_id : string
required subject_fay_id : Fay_ID
required terminal_id : Terminal_ID
required grants : array<Grant> (len 1..256)
required issued_at : timestamp
required not_before : timestamp
required not_after : timestamp
optional grantor_id : string
optional metadata : map<string, string>
}
| 필드 | 제약 | 설명 |
|---|---|---|
descriptor_id | required, unique | 본 자격 증명의 글로벌 고유 식별자 |
issuer_id | required | 발급자 식별자, 키 신뢰 경로의 Descriptor_Issuer에 대응 |
subject_fay_id | required | 인가되는 Fay 식별자 |
terminal_id | required | 인가 범위를 한정하는 단말 식별자 |
grants | required, 1..256 개 요소 | 구체적 인가 항목 목록(§2.3.4 참조) |
issued_at | required | 발급 시각 |
not_before | required, ≥ issued_at | 발효 시작 시각 |
not_after | required, > not_before | 만료 시각 |
grantor_id | optional | 인가자 식별자(Natural_Person 또는 Official_Post) |
metadata | optional | 발급자 커스텀 메타데이터, 프로토콜 시맨틱에 영향 없음 |
구현은 MUST 다음 조건을 충족하지 않는 Authorization_Descriptor를 거부한다:
not_after - not_before > 90일: 본 사양은 단일 자격 증명의 최대 유효 기간을 90일로 한정한다not_before > 현재 시각 + 24시간: 너무 일찍 발효되는 자격 증명 발급을 금지한다(사전 발급 남용 방지)grants배열이 빈 경우: 인가 항목이 없는 자격 증명은 무의미하다
2.3.3 DescriptorSignature
DescriptorSignature {
required algorithm : enum["ed25519", "ecdsa-p256-sha256"]
required key_id : string
required signature_value : bytes
}
| 필드 | 설명 |
|---|---|
algorithm | 서명 알고리즘, 제 8 장 참조 |
key_id | 서명에 사용된 키 식별자, Verification_Key 식별자에 대응 |
signature_value | payload의 CBOR 시리얼라이즈 바이트에 대한 서명 결과 |
서명 입력: DescriptorPayload를 RFC 8949 CBOR 결정적 인코딩(Deterministic Encoding)으로 바이트 시퀀스로 시리얼라이즈하여 서명 알고리즘의 입력으로 한다.
2.3.4 Grant
Grant {
required resource_pattern : string
required modes : array<AccessMode> (len 1..4)
optional constraints : map<string, string>
}
| 필드 | 설명 |
|---|---|
resource_pattern | 리소스 매칭 패턴(§2.3.5 참조) |
modes | 인가된 접근 모드 목록, 요소 타입 AccessMode |
constraints | 부가 제약(시간 윈도우, 지리 펜스 등), 프로토콜 시맨틱에 대한 영향은 제 7 장 참조 |
2.3.5 리소스 매칭 패턴
resource_pattern은 다음 매칭 구문을 지원한다:
- 정확 매칭:
terminal:xxx/device/camera/front - 와일드카드 매칭:
terminal:xxx/device/camera/*(해당 단말의 모든 카메라 매칭) - 전체 단말 매칭:
terminal:xxx/device/camera/**(해당 경로 하 모든 계층 매칭)
구현은 MUST:
- 위 3 종류 구문만 지원하며, 다른 특수 문자를 포함하는 패턴을 거부한다
- 와일드카드
*는 단일 계층 경로 세그먼트만 매칭한다 - 와일드카드
**는 패턴 끝에만 출현할 수 있다
2.3.6 AccessMode
AccessMode = enum["read", "write", "execute", "configure"]
각 접근 모드의 시맨틱은 제 7 장 참조.
2.4 Trusted_Ticket
Trusted_Ticket은 온라인 인가 자격 증명이다. 그 구조는 RFC 7515 JWS Compact Serialization에 기반한다.
2.4.1 최상위 구조
Trusted_Ticket은 JWS 문자열로, .으로 구분된 3 부분으로 구성된다:
base64url(header) . base64url(payload) . base64url(signature)
2.4.2 Header
TicketHeader {
required alg : enum["EdDSA", "ES256"]
required typ : "cap-ticket+jws"
required kid : string
}
| 필드 | 설명 |
|---|---|
alg | 서명 알고리즘(§8과 일치) |
typ | 고정 값 "cap-ticket+jws", 티켓 종류 구별에 사용 |
kid | 키 식별자, 서명 검증에 사용 |
2.4.3 Payload
TicketPayload {
required jti : uuid // 티켓 고유 ID
required iss : string // Ticket_Issuer 식별자
required sub : Fay_ID // 인가되는 Fay
required aud : Terminal_ID // 대상 단말
required iat : timestamp // 발급 시각
required nbf : timestamp // 발효 시작 시각
required exp : timestamp // 만료 시각
required grants : array<Grant> // §2.3.4와 동일 구조
optional convertible : boolean (default true) // Authorization_Descriptor로 변환 가능 여부
}
구현은 MUST exp - nbf > 7일인 Trusted_Ticket을 거부한다. 온라인 티켓의 최대 유효 기간은 오프라인 인가보다 짧으며, 온라인 폐기 메커니즘이 신속히 발효될 수 있도록 보장한다.
2.4.4 Trusted_Ticket에서 Authorization_Descriptor로의 변환
convertible == true인 경우, 단말은 MAY Trusted_Ticket을 로컬 Authorization_Descriptor 형식으로 변환하여 오프라인 사용에 제공할 수 있다. 변환 규칙:
| TicketPayload 필드 | DescriptorPayload 필드로의 매핑 |
|---|---|
jti | descriptor_id |
iss | issuer_id |
sub | subject_fay_id |
aud | terminal_id |
iat | issued_at |
nbf | not_before |
exp | not_after(단, MUST iat + 7일을 초과하지 않음) |
grants | grants |
변환 후의 Authorization_Descriptor는 단말이 로컬 보관 키를 사용하여 재서명하며, 서명 key_id는 변환 출처로 표시된다(제 4 장 참조). 원본 Trusted_Ticket의 서명 정보는 MUST 감사용으로 metadata에 보존된다.
2.5 Session
Session은 단말 내부의 세션 상태 구조이며, 프로토콜 메시지로 완전한 구조를 전송하지 않는다. 본 절은 Session의 필드를 정의하여 상태 머신과 인터페이스 규약을 규범화한다.
Session {
required session_id : Session_ID
required fay_id : Fay_ID
required runtime_id : string
required resource_id : Resource_ID
required access_mode : AccessMode
required granted_modes : array<AccessMode>
required state : SessionState
required created_at : timestamp
required last_heartbeat_at : timestamp
required credential_ref : CredentialRef
}
SessionState = enum[
"creating",
"active",
"handover_pending",
"terminating",
"terminated"
]
CredentialRef {
required type : enum["descriptor", "ticket"]
required id : string // descriptor_id 또는 jti
required not_after : timestamp
}
SessionState 상태 머신은 제 5 장 참조.
2.6 프로토콜 메시지 캡슐화
iFay_Runtime과 Protocol_Engine 간의 모든 메시지는 다음 캡슐화 구조를 공유한다:
ProtocolMessage {
required version : uint32 (= 1)
required message_id : uuid
required message_type : string
required timestamp : timestamp
required sender_id : string
required body : object
optional correlation_id : uuid
}
| 필드 | 설명 |
|---|---|
version | 프로토콜 버전 번호, v1은 1로 설정 |
message_id | 본 메시지의 고유 식별자 |
message_type | 메시지 종류 리터럴(예: "AuthRequest") |
timestamp | 메시지 전송 시각 |
sender_id | 송신자 식별자(runtime_id 또는 terminal_id) |
body | 메시지 본체, 구조는 message_type으로 결정됨 |
correlation_id | 관련 요청 메시지 ID(응답 메시지는 MUST 본 필드를 설정한다) |
각 message_type에 대응하는 body 구조는 해당 장에서 정의된다.
2.7 Verification_Key
Verification_Key는 단말이 보유하는 서명 검증 키다.
VerificationKey {
required key_id : string
required algorithm : enum["ed25519", "ecdsa-p256-sha256"]
required key_material : bytes // 공개 키 바이트
required issuer_id : string // 해당 키에 대응하는 발급자 식별자
required valid_from : timestamp
optional valid_until : timestamp
required source : enum["pre-installed", "ra-distributed"]
}
| 필드 | 설명 |
|---|---|
key_id | 키 식별자, DescriptorSignature.key_id에 대응 |
algorithm | 해당 키가 지원하는 서명 알고리즘 |
key_material | 공개 키의 원시 바이트, 인코딩은 algorithm으로 결정(제 8 장 참조) |
issuer_id | 해당 키에 대응하는 Descriptor_Issuer 식별자 |
valid_from | 키 발효 시작 시각 |
valid_until | 키 만료 시각, 미설정은 장기 유효를 의미 |
source | 키 출처: pre-installed(단말 출고 시 프리인스톨) 또는 ra-distributed(Registration_Authority 온라인 배포) |
단말은 MUST 모든 Verification_Key를 안전하게 보관한다(제 8 장 참조).
2.8 폐기 선언
폐기 선언은 어떤 자격 증명이 폐기되었음을 단말에 알리는 데 사용된다.
RevocationStatement {
required version : uint32 (= 1)
required revocation_id : uuid
required target_descriptor_id : Descriptor_ID
required issuer_id : string
required revoked_at : timestamp
optional reason : enum["unspecified", "compromised", "superseded", "no_longer_needed"]
required signature : DescriptorSignature
}
폐기 선언은 MUST 원본 Authorization_Descriptor의 issuer_id에 의해 발급되고 서명된다.
2.9 시리얼라이제이션과 전송
CAP 프로토콜은 다음 시리얼라이제이션 형식을 사용한다:
| 데이터 구조 | 시리얼라이제이션 형식 | 용도 |
|---|---|---|
| AuthorizationDescriptor | RFC 8949 CBOR(결정적 인코딩) | 오프라인 보관과 전송 |
| Trusted_Ticket | RFC 7515 JWS Compact Serialization | 온라인 전송 |
| ProtocolMessage | JSON(UTF-8) | iFay_Runtime ↔ Protocol_Engine 상호작용 |
| RevocationStatement | RFC 8949 CBOR(결정적 인코딩) | 폐기 목록 배포 |
구현은 MAY ProtocolMessage의 전송 계층에서 JSON 대신 CBOR을 사용하여 오버헤드를 줄일 수 있지만, schema.json에서 정의된 필드명과 시맨틱은 MUST 일치시켜야 한다.
