Faying Protocol/1.0 — §5 Protocol Messages

프로토콜 본문 내비게이션: 장 목차 | 이전 장 §4 데이터 모델 | 다음 장 §6 암호학

§5 Protocol Messages

이 장은 프로토콜의 모든 메시지를 나열한다. 인코딩 규칙, 인벨로프 구조, 일곱 종의 업무 메시지와 한 종의 오류 응답, 그리고 오류 코드와 감사·HP 시야 푸시의 대응 관계를 다룬다.

타입 권위성 안내: 이 장 TypeScript 블록에서 참조하는 Mandate / Scope / Grade / PresenceSignal / PresenceRequirement / Endorsement / SignatureBundle / Attestation / WebAuthnAssertion / AtomicAction / RevokeReason 등 타입의 권위 정의는 §4 Data Models(CDDL)에 있다. TypeScript 뷰는 Non-normative한 사람이 읽는 뷰이며, 둘이 차이를 보이면 §4 CDDL을 정본으로 한다.

§5.1 인코딩 규칙

  • 주 형식(CBOR): 모든 와이어 전송의 기본 인코딩은 CBOR(RFC 8949)다. HTTP Content-Type은 반드시 application/faying-protocol+cbor로 선언해야 한다.
  • 상호운용 폴백(JSON): JSON(RFC 8259)은 디버깅 / 브라우저 / 사람이 읽는 검토 시나리오에서만 사용하며, HTTP Content-Type은 반드시 application/faying-protocol+json으로 명시 선언해야 한다. 보안 등가성은 동일한 필드 의미론과 서명 형식이 보장한다.
  • Deterministic Encoding: 모든 서명 객체는 서명 전에 먼저 RFC 8949 §4.2.1 Deterministic Encoding 규칙에 따라 CBOR 직렬화를 수행하여 JSON 직렬화 모호성을 피해야 한다. JSON 형태에서도 서명 입력은 여전히 Deterministic CBOR 직렬화된 바이트열의 해시다(§6.3 참조).
  • 전송 바인딩: 기본은 HTTP/1.1과 HTTP/2이며, Mandate Service 엔드포인트는 POST /faying-protocol/v1/{verb}를 따른다. gRPC(faying-protocol.v1 service) 또는 WebSocket / SSE(faying-protocol.v1 streaming)에 바인딩할 수도 있다. 모든 전송 계층 바인딩은 메시지 계층 서명과 nonce를 보존해야 하며, 전송 계층 TLS 채널 신원으로 메시지 수준 서명을 대체하는 것은 금지된다.

§5.2 인벨로프 구조

모든 메시지는 통일 인벨로프 FayingProtocolEnvelope를 사용한다.

interface FayingProtocolEnvelope<TPayload> {
  header: {
    version:    "Faying Protocol/1.0";
    msg_type:   FayingProtocolMsgType;
    msg_id:     string;        // ULID
    issued_at:  IsoTime;
    expiry:     IsoTime;
    nonce:      Nonce;
    grade:      Grade;         // 현재 세션 등급(RP가 낮은 등급 요청을 거부하는 데 사용)
    issuer:     HumanPrimeID | string;
    subject:    FayID;
  };
  claims:      TPayload;
  attestation: Attestation;
  signature:   SignatureBundle;
}

type FayingProtocolMsgType =
  | "BOOTSTRAP"        | "BOOTSTRAP_RESP"
  | "PRESENCE"         | "PRESENCE_ACK"
  | "GRADE_SWITCH"     | "GRADE_SWITCH_RESP"
  | "DELEGATE"         | "DELEGATE_RESP"
  | "REVOKE"           | "REVOKE_RECEIPT"
  | "FAYING_REQUEST"   | "FAYING_REQUEST_RESP"
  | "DISCLOSURE"
  | "ERROR";

인벨로프 계층 불변식:

  • 어느 필드든 누락되거나 타입이 잘못되면 일률적으로 E_PROTOCOL로 거부한다(§5.4 참조).
  • nonce는 2 × max_message_lifetime 창 안에서 동일 subject에 대해 최대 한 번만 수용된다. 중복이면 E_REPLAY.
  • expiry는 반드시 유한하고 > issued_at이어야 한다. 만료된 인벨로프는 업무 검증 경로에 진입하지 않고 곧바로 E_PROTOCOL로 거부된다.
  • signature의 입력은 반드시 H( Deterministic-CBOR( Envelope_without_signature ) )여야 한다(§6.3 참조).

§5.3 메시지 목록

본 프로토콜은 총 7종의 업무 메시지를 정의한다: BOOTSTRAP / PRESENCE / GRADE_SWITCH / DELEGATE / REVOKE / FAYING_REQUEST / DISCLOSURE, 여기에 1종의 오류 응답 ERROR를 더한다(§5.4 참조).

§5.3.1 BOOTSTRAP(Faying Action)

용도: Human Prime이 BOOTSTRAP을 통해 MS에서 Mandate 한 건을 수립하고 iFay에게 감호 인가를 발급한다. BOOTSTRAP은 Faying Protocol의 유일한 합법 Faying Action 입구다.

interface BootstrapClaims {
  human_prime:   HumanPrimeID;
  fay:           FayID;
  scope:         Scope;
  grade:         Grade;
  presence_req:  PresenceRequirement;
  not_after:     IsoTime;          // 반드시 유한
  human_witness: WebAuthnAssertion; // user-verification = true
  endorsement?:  Endorsement;       // 선택; 존재 시 Endorsed Mandate 발급(§4 / §11 참조)
  faying_request_ref?: string;      // IF-initiated 경로에서 대응 FAYING_REQUEST.msg_id 참조
}

성공 응답: 완전한 Mandate 객체(signature_bundle 포함) 반환.

프로토콜 계층 하드 제약:

  • not_after는 반드시 유한하고 > not_before여야 하며 ∞와 음수는 금지된다. 위반 시 일률적으로 E_PROTOCOL로 거부한다(§3.1 I-MS-1 / Property 7과 일치).
  • human_witness 필드가 누락되거나 서명 검증에 실패하면 일률적으로 E_HUMAN_WITNESS_REQUIRED로 거부한다. IF / MS / Supervisory Agent가 HP를 대신해 승인 확인을 완료하는 합법 경로는 없다.
  • BOOTSTRAP이 이전에 iFay가 발기한 FAYING_REQUEST에 응답할 때, faying_request_ref는 반드시 그 요청의 msg_id를 가리켜야 한다. MS는 Attestation Chain 위에 "iFay 발기 → HP 입회 → 발효" 세 단계를 분리 불가능한 한 줄의 증거 체인으로 엮어야 한다(§5.3.6, §3.3 참조).
  • endorsement 필드가 존재할 때, MS는 발급 전에 endorsed_scope ⊆ scope ∧ endorsed_grade.autonomy ≤ grade.autonomy ∧ 0 < endorsed_lifetime_ms ≤ (not_after − not_before)를 검증해야 한다. 어느 하나라도 만족하지 못하면 E_ENDORSEMENT_INVALID(오류 코드 1013)로 거부한다.

§5.3.2 PRESENCE(지속적 보정)

용도: iFay_Instance가 주기적으로 Presence Device가 생성한 재현 신호를 MS에 푸시하여 대응 Mandate의 PresenceState.last_freshness를 갱신한다.

interface PresenceClaims {
  mandate_id:    MandateID;
  signal:        PresenceSignal;
  device_health: {
    secure_element: boolean;
    tampered:       boolean;
    last_boot_at:   IsoTime;
  };
}

프로토콜 계층 하드 제약:

  • signal은 반드시 §3.2 I-PC-1 강제 삼중쌍(nonce / produced_at / device_attestation)을 담고 Presence Device가 서명해야 한다. 하나라도 빠지면 E_PROTOCOL. 신선도 창은 대응 Mandate의 presence_req.max_staleness_ms가 부여하며 신호가 자체적으로 갖지 않는다.
  • 신호가 presence_req.max_staleness_ms를 초과하면 E_PRESENCE_STALE이며, §3.2 I-PC-3에 따라 조임을 트리거한다(더 엄격한 grade 또는 Suspended로 전이).
  • 동일 (subject, nonce)가 2 × max_message_lifetime 창 안에서 중복 출현하면 일률적으로 E_REPLAY.

§5.3.3 GRADE_SWITCH(등급 전환)

용도: Mandate 생명주기 내에서 인가 등급을 조정(승급 / 강등)한다.

interface GradeSwitchClaims {
  mandate_id:    MandateID;
  target_grade:  Grade;
  reason:        "human-initiated" | "presence-loss" | "policy-trigger";
  human_witness?: WebAuthnAssertion;  // 승급 방향 필수, 강등 방향 선택
}

프로토콜 계층 불변식(승급 강제 입회): target_grade.autonomy > current.autonomy(즉 자율성 방향에서 현재 등급보다 엄격히 강할 때)일 때 human_witness는 MUST다. 누락되거나 서명 검증에 실패하면 일률적으로 E_HUMAN_WITNESS_REQUIRED로 거부한다. 강등 방향(target_grade.autonomy ≤ current.autonomy)은 프로토콜이 자동 트리거하는 것을 허용하며(예: presence-loss / policy-trigger), human_witness를 강제하지 않는다.

§5.3.4 DELEGATE(디바이스 간 / 하위 대리 파생)

용도: 부모 Mandate에서 자식 Mandate를 파생하며, 디바이스 간 또는 하위 대리 시나리오에 사용한다.

interface DelegateClaims {
  parent_mandate: MandateID;
  child_subject:  FayID;            // 파생체 FayID
  child_scope:    Scope;            // 반드시 ⊆ parent.scope
  child_grade:    Grade;            // child_grade.autonomy는 반드시 ≤ parent.grade.autonomy(자율성이 더 낮거나 같음, 즉 더 엄격하거나 같음)
  device_id?:     string;           // 디바이스 간 파생 시 구체 단말에 결속
}

프로토콜 계층 하드 제약:

  • child_scope ⊆ parent.scope ∧ child_grade.autonomy ≤ parent.grade.autonomy. 어느 방향이든 확장은 E_PROTOCOL로 거부한다(§3.1 I-MS-4 / Property 6과 일치).
  • 자식 Mandate의 signature_bundle.chain은 반드시 부모 Mandate의 부서명을 담아 Attestation Chain 위의 한 파생 노드를 구성해야 한다.
  • 부모 Mandate가 endorsement를 담을 때, 자식 Mandate의 endorsement(존재 시)는 반드시 부모 endorsement에 수렴해야 한다. 수렴하지 않으면 E_ENDORSEMENT_INVALID로 거부한다.

§5.3.5 REVOKE

용도: Mandate 한 건을 폐기한다. 선택적으로 그 모든 파생 자식 Mandate를 연쇄 폐기할 수 있다.

interface RevokeClaims {
  mandate_id:   MandateID;
  cascade:      boolean;            // 모든 파생 자식 Mandate를 연쇄 폐기할지 여부(기본 true)
  reason:       RevokeReason;
  effective_at: IsoTime;            // 기본 = now, 예약 폐기 허용
}

type RevokeReason =
  | "human-initiated"
  | "expiry"
  | "task-completed"
  | "human-prime-unreachable"
  | "ego-deviation"
  | "fay-credential-invalid"
  | "human-prime-credential-invalid"
  | "regulatory-order"
  | "terminal-disconnected";

RevokeReason은 §13장의 아홉 가지 트리거 조건과 일대일 대응한다.

프로토콜 계층 하드 제약:

  • 폐기 도달성은 반드시 ≥ Bootstrap 도달성이어야 한다(Property 4 / R4.1과 일치). iFay 자신이 합법적으로 REVOKE를 발기하는 경로는 없다.
  • cascade = true일 때 모든 파생 자식 Mandate는 반드시 RevocationVisibilityBudget 내에 revoked로 가시화되어야 한다(Property 14와 일치).
  • 폐기는 되돌릴 수 없다: Revoked는 흡수 상태이며, 인가를 복구하려면 반드시 BOOTSTRAP을 다시 거쳐야 하고 새 mandate_id는 옛 mandate_id와 같지 않다(Property 10과 일치).

§5.3.6 FAYING_REQUEST / FAYING_REQUEST_RESP(IF-initiated 양방향 Faying)

용도: iFay가 능동적으로 Human Prime에게 Faying을 요청한다(감호 관계 수립 또는 조정 요청). 이 메시지는 Mandate를 직접 생성하지 않는다. MS는 전달자로서만 요청을 HP 시야 통로로 푸시하고, 이후 HP가 BOOTSTRAP을 통해 승인 발효를 완료한다(§2.4 Phase A0 참조).

interface FayingRequestClaims {
  initiator:        FayID;          // iFay 자신
  target_human:     HumanPrimeID;   // 목표 HP
  proposed_scope:   Scope;          // 제안하는 감호 범위
  proposed_grade:   Grade;          // 제안하는 등급
  reason:           string;         // 자유 텍스트 보충
  reason_code:
    | "establish"
    | "adjust-scope"
    | "adjust-grade"
    | "renew"
    | "endorsement-request";
  expected_lifetime_ms?: number;    // 기대하는 Mandate 수명
  proposed_endorsement?: Endorsement; // Endorsed Mandate도 함께 요청하는 경우
}

interface FayingRequestRespClaims {
  request_msg_id: string;           // 상류 FAYING_REQUEST.msg_id 참조
  status:         "accepted" | "rejected" | "timeout";
  bootstrap_ref?: string;           // status=accepted일 때 HP가 완료한 BOOTSTRAP.msg_id를 가리킴
  reject_reason?: string;
}

프로토콜 계층 하드 제약:

  • iFay가 능동 발기한 FAYING_REQUEST는 어떤 Faying 상태 변화도 직접 일으키지 않는다. 오직 HP가 BootstrapTimeout 내에 BOOTSTRAP(faying_request_ref와 검증 가능한 human_witness 휴대)으로 응답해야 요청이 발효된다.
  • HP가 BootstrapTimeout 내에 명확한 승인 확인을 내놓지 않으면, MS는 반드시 FAYING_REQUEST_RESP { status="timeout" }을 반환하고 이벤트를 Attestation Chain에 기록한다. 대응 오류 코드는 E_FAYING_REQUEST_NOT_CONFIRMED(1014)다.
  • MS / IF / Supervisory Agent가 HP를 대신해 승인 확인을 완료하는 합법 경로는 일절 없다. human_witness가 빠지면 일률적으로 E_HUMAN_WITNESS_REQUIRED(1010).
  • 각 (HP, IF) 쌍의 FAYING_REQUEST 빈도는 ConfirmationRateLimit(부록 B 참조) 제약을 받으며, 초과 시 §9.10.7 T6에 따라 처리한다.

§5.3.7 DISCLOSURE(구조화 공개 메시지)

용도: iFay가 보고 또는 확인 요청 시 사용하는 구조화 공개 메시지다. 규제 측과 MS는 이 메시지에 대해 schema 수준 감사를 수행할 수 있으며, 순수 자유 텍스트로 핵심 정보를 가리는 것은 금지된다(§9.10.4 T3 참조).

interface DisclosureClaims {
  mandate_id:         MandateID;
  /** mandatory_fields(어느 하나라도 빠지면 프로토콜 오류로 간주) */
  action:             AtomicAction;          // 한 번의 공개는 정확히 하나의 Atomic_Action에 대응
  scope_used:         Scope;                 // 실제 사용한 scope 부분집합
  risk_level:         "low" | "normal" | "high" | "critical";
  reversibility:      "reversible" | "partially-reversible" | "irreversible";
  affected_resources: string[];
  uncertainty_flags:  string[];              // 예: ["ambiguous-target", "stale-context"]
  /** 선택 보충 */
  free_text?:         string;
  intent?:            "report" | "request-confirmation";
  endorsement_id?:    string;                // Disconnected 기간에 발생 시 대응 endorsement를 가리킴
}

mandatory_fields 강제 목록(R13.3 / §9.10.4와 일치):

action / scope_used / risk_level / reversibility / affected_resources / uncertainty_flags.

프로토콜 계층 하드 제약:

  • 어느 mandatory_fields라도 누락되거나 파싱 불가 → MS는 반드시 E_PROTOCOL(1099)로 거부하고 HP 시야 통로로 푸시한다.
  • 고민감 동작(risk_level ∈ {high, critical})은 D 차원 실행 이전에 먼저 DISCLOSURE를 발송하고 HP의 명시 확인을 기다려야 한다(현재 grade가 이미 G4 Autonomous이고 동작이 주 scope 안에 떨어지는 경우는 예외, §7 참조).
  • 이후 감사에서 DISCLOSURE의 mandatory_fields가 실제 동작과 불일치함이 발견되면, MS는 반드시 RevokeReason="ego-deviation"으로 해당 Mandate를 폐기해야 한다.
  • Disconnected 기간에 실행된 동작의 DISCLOSURE는 반드시 endorsement_id를 담아, 그 동작이 구체적인 한 건의 endorsement로 독립 추적될 수 있게 해야 한다.

§5.4 오류 코드

오류 응답은 통일적으로 ERROR 메시지(인벨로프 msg_type = "ERROR")를 사용하며, claims 본체는 { code, message, mandate_id?, recovery_hint? } 형태다. 아래 표는 모든 오류 코드와 그 감사·HP 시야 푸시 제약을 제시한다(§EH.3과 일치).

Code명칭의미응답감사 필수HP 시야 필수
1001E_NO_MANDATE요청에 Mandate 미휴대거부✗✗
1002E_MANDATE_EXPIREDMandate 만료됨거부 + Revoke 트리거✓✗
1003E_SCOPE_VIOLATION호출이 scope 초과거부 + 의심 기록✓✗
1004E_GRADE_INSUFFICIENT현재 등급이 해당 민감 동작을 실행하기에 부족거부 + 승급 안내✓✗
1005E_PRESENCE_STALE재현 신호 만료거부 + 강등 트리거✓✗
1006E_REVOKEDMandate 이미 폐기됨거부✓✓
1007E_ATTESTATION_INVALIDAttestation 검증 실패거부 + Revoke 트리거✓✓
1008E_RR_UNAVAILABLE폐기 등록 센터 도달 불가Default-Deny에 따라 거부✓✗
1009E_REPLAYnonce 중복거부 + 보안 경보✓✓
1010E_HUMAN_WITNESS_REQUIRED등급 승급 / 양방향 Faying에 인간 입회 누락거부✓✗
1011E_ROGUE_DETECTEDRogue 행위 감지거부 + 강제 Revoke✓✓
1012E_BUDGET_EXCEEDEDResourceBudget 초과거부 + 강등 트리거✓✗
1013E_ENDORSEMENT_INVALIDEndorsement 필드 불법(endorsed_scope ⊄ scope / endorsed_grade.autonomy > grade.autonomy / endorsed_lifetime 누락 또는 초과 / 변조 포함)거부 + 해당 Mandate의 Revoke 트리거✓✓
1014E_FAYING_REQUEST_NOT_CONFIRMEDiFay가 능동 발기한 FAYING_REQUEST가 BootstrapTimeout 내에 HP 명확 승인 미획득거부 + Attestation Chain에 기록✓✗
1099E_PROTOCOL프로토콜 계층 오류(버전 / 형식 / 서명 / DISCLOSURE mandatory_fields 누락 또는 파싱 불가)거부✓✗*

* 주: E_PROTOCOL은 기본적으로 감사에만 기입된다. 단 §5.3.7 DISCLOSURE의 mandatory_fields 누락 또는 파싱 불가 경로에서 트리거되면, MS는 반드시 추가로 HP 시야 통로로 푸시해야 한다(§5.3.7, §9.10.4 T3 참조).

감사 / HP 시야 의미론 설명:

  • 감사 필수: 오류는 반드시 (error_code, mandate_id, ts, RP_id, reason) 5요소로 Attestation Chain / audit-log에 기입되어야 한다. E_NO_MANDATE(Mandate 컨텍스트 없음)를 제외한 모든 오류 코드가 ✓다.
  • HP 시야 필수: 오류는 반드시 HP 시야 통로로 push되어야 하며, RP가 조용히 삼키는 것은 금지된다. 기본 네 종(E_REVOKED / E_ATTESTATION_INVALID / E_REPLAY / E_ROGUE_DETECTED)은 §EH.3이 강제한다. E_ENDORSEMENT_INVALID는 그 트리거 경로가 반드시 E_REVOKED를 동반하므로 HP 시야 통로로도 푸시된다.
  • 오류 응답에는 MS 내부 상태, Mandate 개인키 지문, 다른 Human Prime 식별자 등 민감 정보를 담는 것이 금지된다(§EH.3 참조).