1. 개요
WAVE Protocol Stack
IEEE 1609.2
- WAVE 통신의 보안을 담당하는 표준
- 인증서 기반 인증 및 관리, 메시지 암호화, 서명 등을 처리하는 방식 정의
- 기밀성, 무결성, 인증 및 접근 제어 기능을 제공
- Message 데이터를 보호하고 신뢰성 있는 통신을 보장하기 위해 제공되는 메커니즘
- Management Message
- 보안 관리 관련 메시지로 보안 관리와 관련된 메타데이터를 담고 있는 메시지
- 인증서 관리(발급, 검증, 갱신 등)와 관련된 정보가 담길 수 있으며 보안 상태를 점검하거나 관리하는데 사용
- Application Message
- 사람, 차량, 인프라 등 어플리케이션 간 통신을 위한 메시지로 실제 서비스와 관련된 정보를 담고 있는 메시지
- 안전 경고, 교통 정보, 신호등 상태 등 실제 응용 프로그램 계층에서의 데이터 교환 목적
IEEE 1609.2가 답하려는 질문
- V2X 통신의 보안 위협
- 스푸핑, 변조, 재전송 공격, 도청
- 스푸핑 : 다른 송신자가 보낸 것처럼 가장
- 변조 : 메시지 내용을 변경
- 재전송 공격 : 이전 메시지를 다시 보내 수신자의 동작을 유도
- 도청 : 제 3자가 통신 내용을 수집하거나 열람
V2X 통신 시 보안 위협으로 부터 메시지를 받았다는 사실만으로는 신뢰할 수 없음.
따라서 IEEE 1609.2는 메시지를 보호하고 검증하기 위한 형식과 처리 규칙을 정의함.
- 결국 1609.2는 수신자가 메시지 하나를 받았을 때 던지는 질문들에 답하기 위한 표준이다.
- 아래 ASN.1 구조체의 필드들은 모두 이 질문 중 하나에 대한 답이다.
| 수신자의 질문 | 답해주는 구조/필드 |
|---|
| 중간에 위변조되지 않았나? | SignedData.signature, hashId, tbsData |
| 누가 보냈나? 그 사람을 믿어도 되나? | signer(digest / certificate) → 인증서 체인 → Trust Anchor |
| 이 사람이 이 종류의 메시지를 보낼 자격이 있나? | HeaderInfo.psid ↔ 인증서의 appPermissions(PSID / SSP) |
| 지금, 여기서 만든 메시지인가? (재전송 공격 방지) | generationTime, expiryTime, generationLocation ↔ 인증서의 validityPeriod, region |
| 이 인증서가 폐기되지는 않았나? | cracaId, crlSeries, LinkageData → CRL (CRLVE, SSME) |
| 서명자 인증서를 모르면 어떻게 하나? | signer가 digest뿐일 때 → p2pcdLearningRequest / P2PCD |
| 특정 수신자만 읽게 하려면? | EncryptedData, RecipientInfo, DEK |
2. WAVE Reference Model
컴포넌트 한눈에 보기
- 누가 누구에게 무엇을 해주는지로 정리하면 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| SDEE (애플리케이션: BSM, SPaT 등)
│ "이 PDU를 PSID=X로 서명/암호화해줘" (키는 CMH로만 지정)
▼
SDS ──────────── SPDU 생성 / 처리 (서명, 검증, 암호화, 복호화)
│ ▲
│ │ 인증서, 신뢰 앵커, 폐기 정보 조회
▼ │
SSME ─────────── 인증서 · CRL · Trust Anchor 저장소
▲ ▲
│ │
CRLVE P2PCDE
(CRL 검증) (모르는 인증서를 이웃에게 요청/제공)
CMH ──────────── 개인키 등 암호 자료를 가리키는 핸들 (실제 키는 HSM 등에 격리)
|
SDEE (Secure Data Exchange Entity)
- 보안 데이터 교환 개체
- SDS를 이용해 SPDU를 주고받는 개체로, 주로 애플리케이션이다. (예: BSM 앱, 신호등(SPaT) 앱)
- 한 단말 안에 SDEE가 여러 개 있을 수 있고, 보안 서비스(SDS, SSME, P2PCDE 등)는 단말에 하나로 이들이 함께 사용한다.
- SDEE가 하는 일
- 보낼 때 : PDU와 PSID, CMH를 SDS에 넘기며 서명·암호화를 요청한다.
- 받을 때 : 받은 SPDU를 SDS에 넘기며 전처리·검증·복호화를 요청하고, 결과로 얻은 payload를 사용한다.
- SDEE가 하지 않는 일
- 개인키를 직접 다루지 않는다. CMH 번호로만 가리킨다.
headerInfo의 보안 관리 정보(P2PCD 요청 등)는 SDS / P2PCDE가 처리하며, SDEE는 payload만 신경 쓴다.
- 보안 동작(서명 여부, 신선도 기준 등)은 SDEE마다 다를 수 있으며, 이는 해당 SDEE 명세의 보안 프로파일로 정한다.
SDS (Secure Data Service)
- SDEE(Secure Data Exchange Entity)간의 메시지 송, 수신 시 데이터를 암호화하거나 서명 및 검증 작업 담당
- 메시지 내용에 대한 암호학적 보호, 위, 변조 방지 제공
- 수신한 SPDU의 복호화 및 서명 검증 과정을 위한 보안 관리 정보 제공
- SDS 연산은 SPDU를 생성하거나 처리한다.
SPDU (Security services Protocol Data Units)
- 보안 서비스를 이용하는 SDEE 인스턴스 간에 교환되는 데이터그램이다.
- 목적
- 내용에 대한 암호학적 보호를 제공하기 위해
- 다른 SPDU의 올바른 처리를 가능하게 하기 위해 교환되는 보안 관리 정보를 제공하기 위해
- 비보안(unsecured), 서명됨(signed), 암호화됨(encrypted), 또는 서명된 인증서 요청 유형일 수 있다.
- ASN.1에서는
Ieee1609Dot2Content의 CHOICE로 표현된다.
- 하나의 SPDU는 동일하거나 다른 유형의 또 다른 SPDU를 포함할 수 있다.
- 예) 서명 후 암호화 :
encryptedData 안에 signedData가 들어 있는 구조
SSME (Security Service Management Entity)
- 보안 서비스 관리 개체
- 인증서와 인증서 관련 정보들을 저장하는 개체
- 저장된 정보들은 SDS에 의해 암, 복호화 서명 및 검증에 사용
- CA 인증서들과 로컬 SDEE뿐만 아니라 통신하는 다른 SDEE의 인증서도 함께 저장 및 관리
CMH (Crypto Material Handles)
- 스펙에 정의되어 있는 암호화 작업에 사용되는 암호화 자료를 관리하기 위한 추상적 개념
- 개인 키, 공개 키, 인증서 정보 등을 암호화 작업 시 직접 사용하는 것을 방지
- SDEE는 암호화 작업 시 SDS를 통해 CMH라는 정수 값을 이용해 간접 참조하며 암호화 자료를 사용
- CMH는 키 저장소를 추상화한 것으로 키 관리 기능을 제공하진 않는다.
- 외부로 유출되면 사고를 유발하는 암호화 자료들을 논리적으로 분리하거나 HSM 같은 안전 영역에 저장하여 사고를 방지
- 추상적 개념으로 실제 구현은 설계에 따라 달라지며 아래 요구사항들을 만족해야 한다.
- Keypair 유효성 보장
- Private Key read or modify 방지
- 키 생성을 위한 보안 난수 생성 방법
- 암호화 자료의 메타 데이터(인증서 만료 시간 등) 관리(갱신, 폐지)
- 더 이상 사용하지 않는 CMH에 대한 삭제
3. 시나리오: 서명된 BSM 한 건 따라가기
- 차량 A가 BSM(Basic Safety Message, 차량 위치·속도 등)을 브로드캐스트하고 차량 B가 받는 상황
- 위의 컴포넌트와 아래 부록의 ASN.1 구조체가 어느 단계에서 등장하는지 연결해 본다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| [차량 A] [차량 B]
App(SDEE): BSM 생성
│ "PSID=0x20으로 서명해줘, CMH=3"
▼
SDS ── CMH 3번 키로 서명 (키는 HSM 안, 직접 못 봄)
│ Ieee1609Dot2Data
│ └ signedData
│ ├ hashId = sha256
│ ├ tbsData
│ │ ├ payload.data = BSM (unsecuredData)
│ │ └ headerInfo{psid, generationTime}
│ ├ signer = digest (평소) / certificate (가끔)
│ └ signature
▼
──────────────── 무선 전송 (SPDU) ───────────────▶ SDS
│ ① signer → 서명자 인증서 확보
│ ② 인증서 체인 → Trust Anchor까지 검증
│ ③ 체인 내 인증서 폐기 여부 확인
│ ④ psid ∈ appPermissions ?
│ ⑤ generationTime / 위치가 유효 범위 안?
│ ⑥ signature 검증
▼
App(SDEE): BSM 사용
|
송신 (차량 A)
- 애플리케이션(SDEE)이 BSM을 만들고, SDS에 PSID와 CMH를 넘기며 서명을 요청한다.
- 애플리케이션은 개인키를 직접 다루지 않는다. CMH 번호만 알 뿐이다.
- SDS는
ToBeSignedData를 구성한다.payload : BSM 본문headerInfo : psid, generationTime 등 SDS가 덧붙이는 정보
tbsData를 COER로 인코딩해 해시하고, 서명자 인증서의 해시와 연결한 뒤 CMH가 가리키는 개인키로 서명한다.signer 필드를 채운다.- 대부분은 8바이트짜리
digest(HashedId8)만 넣는다. - 주기적으로(예: 약 1초에 한 번) 또는 새 이웃이 등장했을 때 전체
certificate를 넣는다.
수신 (차량 B)
- 서명자 인증서 확보
signer가 certificate면 그대로 사용하고 SSME에 저장한다.digest면 SSME에서 같은 HashedId8의 인증서를 찾는다.- 없다면 → 다음에 보낼 메시지의
headerInfo.p2pcdLearningRequest에 HashedId3를 실어 이웃에게 요청한다. (P2PCD)
- 체인 검증 : 서명자 인증서 → 발급자(
issuer) → … → Trust Anchor까지 연결되는지 확인한다. - 폐기 여부 : 체인 내 인증서가 CRL에 포함되어 있지 않은지 SSME에 저장된 폐기 정보로 확인한다. (CRL은 CRLVE가 검증해 SSME에 넣어둔 것)
- 권한 확인 :
headerInfo.psid가 서명자 인증서의 appPermissions에 포함되는지, SSP가 허용하는 내용인지 확인한다. - 시간·위치 확인 :
generationTime이 인증서 validityPeriod 안인지, 너무 오래된 메시지(재전송)가 아닌지, 위치가 인증서 region 안인지 확인한다. - 서명 검증 : 인증서의 공개키(implicit이면 재구성한 공개키)로
signature를 검증한다. - 모두 통과하면 BSM을 애플리케이션에 전달한다.
여기서 나오는 “왜?”
- 왜 signer를 보통 digest로 보낼까?
- BSM은 초당 10회씩 전송되는데, 매번 인증서(100바이트 이상)를 붙이면 채널 부하가 크다.
- 그래서 평소엔 8바이트 digest만 보내고 → 모르는 인증서가 생길 수 있으니 → P2PCD가 필요해진다.
- 왜 implicit 인증서가 있을까?
- 같은 이유(크기). 서명과 공개키 대신 재구성 값 하나만 담아 인증서를 작게 만든다.
- 왜 인증서에 이름 대신 linkage 값이 들어갈까?
- 차량이 같은 인증서를 계속 쓰면 위치를 추적당한다. 그래서 짧은 기간마다 바뀌는 가명 인증서(pseudonym certificate)를 쓰고, 폐기할 때는 linkage 값으로 한 차량의 인증서 묶음을 한꺼번에 폐기한다.
- 이 발급·폐기 체계는 IEEE 1609.2.1 / SCMS에서 다룬다.
4. 인증서
- 서명 검증 키와 그 키의 사용 권한을 담고, issuer가 서명(또는 재구성 정보)으로 보증한 데이터 구조
CA Certificate
- 신뢰할 수 있는 중앙 인증 기관이 서명한 인증서로 인증서 발급에 사용되는 인증서
- 인증서 체인을 구성하며 신뢰의 고리를 형성
Certificate Chain
- 상위에 있는 인증서에 의해 발급된 각 인증서가 정렬된 인증서 세트
- Complete Certificate Chain : 최상위 인증서 ~ 최하위 인증서
- Partial Certificate Chain : 완전한 인증서 체인이 아닌 인증서 체인 (최상위 인증서가 루트 인증서가 아니거나 최하위 인증서가 최종 엔티티 인증서가 아닌 경우)
- Root Certificate : 다른 인증서를 검증하기 위한 신뢰 앵커(Trust Anchor)로 사용되는 자체 서명 인증 기관 인증서
- Intermediate Certificate : Root Certificate에서 파생된 인증서
- Trust Anchor : 신뢰의 기준점이 되는 인증서
- 그 자체로 신뢰를 보장하며 인증서 체계의 최상위에 있는 인증서 체인의 출발점이 되는 인증서
- Security Service는 시스템 초기화 시 사전 설정된 Trust Anchor 목록 혹은 CTL을 통해 Trust Anchor를 알 수 있다.
Trustworthiness of Certificate Chain
- 각 하위 인증서들은 상위 인증서와 관련되어야 한다.
- 인증서 체인은 Trust Anchor로 시작해야 한다.
- 체인에 포함되어 있는 인증서 중 어느 하나라도 폐기되지 않아야 한다.
Whole Certificate Hash Algorithm
- 인증서를 식별하는 목적으로 인증서를 해시로 계산하는데 사용하는 알고리즘
- 이 해시의 하위 8바이트가 HashedId8, 하위 3바이트가 HashedId3이다. (
signer.digest, issuer, p2pcdLearningRequest 등에서 사용)
권한: PSID와 SSP
- PSID (Provider Service Identifier) : 애플리케이션/서비스를 식별하는 값 (예: BSM)
- SSP (Service Specific Permissions) : 해당 서비스 안에서 구체적으로 어떤 내용을 보낼 수 있는지에 대한 세부 권한
- 인증서 종류별로 들어가는 권한
appPermissions : 이 인증서로 어떤 PSID의 메시지에 서명할 수 있는가 (end-entity, authorization 인증서)certIssuePermissions : 이 인증서로 어떤 PSID의 인증서를 발급할 수 있는가 (CA 인증서)certRequestPermissions : 이 인증서로 어떤 인증서를 요청할 수 있는가 (enrollment 인증서)
Explicit vs Implicit
- 데이터 크기
- Explicit Certificate : 공개 키와 발급자의 서명이 명시적으로 포함되어 있어 사용이 간편하고 직관적이지만, 인증서 크기와 전송 효율 측면에서 비효율적일 수 있다.
- Implicit Certificate : 발급자의 서명과 공개 키 대신 공개키 재구성 값(reconstruction value)만 있어 인증서 자체 크기가 Explicit에 비해 작다.
- 네트워크 부하를 줄이고 단말 자원이 제한적인 상황에서 이점
- 검증 과정
- Explicit Certificate : 발급자의 공개키로 인증서의 서명을 검증하고, 인증서에 들어 있는 공개키로 메시지 서명을 검증한다.
- Implicit Certificate : 발급자의 공개키와 재구성 값으로 공개키를 재구성하고, 그 공개키로 메시지 서명이 검증되면 인증서도 함께 검증된 것으로 본다. (암묵적 검증)
- 인증서 서명 검증은 생략되지만, 공개 키 재구성 과정이 필요하므로 구현이 더 복잡해질 수 있다.
인증서 유효성 : 서명 검증과 정합성, 신뢰성 검증
- 공개키 재구성만으로는 인증서가 확인되지 않고, 서명 검증을 통과해도 정합성, 신뢰성까지 만족해야 최종 유효함
- 서명 검증(암호학적 유효성)
- Explicit : issuer 공개키로 인증서의 서명을 검증
- Implicit: issuer 공개키 + 재구성 값으로 공개키를 재구성하고 그 키로 관련 SPDU의 서명을 검증
- 체인 : 서명 인증서부터 Trust Anchor까지, 발급 단계마다 위 검증을 수행
- 정합성, 신뢰성 검증
- 체인, 신뢰 : Trust Anchor로 시작, 허용된 체인 길이, 폐기되지 않음
- PSID, SSP : PSID가 issuer certIssuePermissions 범위 안
- 기간 : validityPeriod가 issuer 유효기간 안
- 지역 : region이 issuer 지역 안
- 그 밖 : 올바른 인코딩, 검증에 필요한 필드를 모두 해석 가능
Explicit 인증서 체인의 암호학적 검증
- 각 issuer 공개키로 아래 인증서의 서명을, 마지막에 EE 공개키로 SPDU 서명을 검증함
- 체인 구성
- SPDU의 signer로 EE 인증서를 식별하고, 각 인증서의 issuer 필드를 따라 Trust Anchor까지 체인을 구성함
- 인증서 서명 검증
- Trust Anchor부터 아래로, issuer 공개키로 하위 인증서의 서명을 검증함. Root CA 공개키로 EE 인증서를 검증함
- SPDU 서명 검증
- EE 인증서의 공개키로 Signed SPDU의 서명을 검증함
따라서 CA 공개키로 EE 인증서 서명 검증, EE 공개키로 SPDU 서명 검증, 총 검증 2번 실행
- 암호학적 검증 외에 PSID, SSP 권한, 기간, 지역 정합성과 폐기 상태도 따로 확인해야함
Implicit 인증서 체인의 암호학적 검증
따라서 CA 공개키와 재구성 값으로 계산, 재구성한 EE 공개키로 SPDU 서명을 검증 ,총 계산 1번, 검증 1번
Explicit-Implicit 인증서 섞인 체인의 검증
- 공개키 재구성만으로는 암호학적 유효성 미확정
- 재구성은 계산일 뿐이라 위조된 implicit 인증서로도 “어떤 공개키”는 나온다.
- 그 키로 만든 서명이 실제로 검증될 때 비로소 implicit 인증서가 확인된다.
- 위조된 인증서에서 재구성된 키의 개인키는 아무도 모르므로, 그 키로 검증되는 서명을 만들 수 없기 때문
- 왼쪽 : 모두 Explicit
- 인증서마다 issuer 공개키로 그 인증서의 서명을 검증한다.
- 각 단계가 독립적으로 확인되므로, 마지막에 EE 공개키로 SPDU 서명을 검증한다.
- 오른쪽 : 아래쪽 두 개가 Implicit
- 마지막 Explicit CA 인증서의 공개키에서 시작해 차례로 재구성한다.
- Explicit CA 공개키 + CA Implicit 재구성 값 → CA 공개키
- CA 공개키 + EE Implicit 재구성 값 → EE 공개키
- 재구성된 EE 공개키로 SPDU 서명이 검증되면 Implicit 인증서들이 함께 확인된다. (combine to verify)
- 그림에서 각 reconstruction value에서 나온 선이 모두 SPDU 서명 검증으로 모이는 이유
1
2
3
4
5
6
7
8
9
10
| Root CA (Explicit) ── 서명 검증 ──▶ CA (Explicit) ← 여기까지는 단계별로 확정
│ 공개키
▼ + 재구성 값
CA (Implicit) 공개키 ← 아직 미확정
│
▼ + 재구성 값
EE (Implicit) 공개키 ← 아직 미확정
│
▼
SPDU 서명 검증 성공 → Implicit 두 장이 한꺼번에 확정
|
- Implicit 인증서 아래에 Explicit 인증서가 있는 경우
- 재구성된 Implicit CA 공개키 자체는 확인되지 않은 키다.
- 하지만 그 키로 하위 Explicit 인증서의 서명이 검증되면, 그 순간 Implicit CA 인증서도 확인된다.
- 하위 인증서의 서명이 SPDU 서명과 같은 “검증되는 서명” 역할을 하기 때문
- 즉 Implicit 인증서는 자기 키로 만든 다음 서명(하위 인증서든 SPDU든)이 검증될 때 확정된다.
- 그러나 표준상으로는 제약을 둠
- 문서 자체에 이유는 나오진 않았지만, Explicit 인증서는 크기(서명 포함)를 더 쓰는 대신, 체인 위로 끝까지 SPDU 없이도 제 3자가 독립적으로 검증할 수 있다는 장점이 는데, 발급자가 implicit이면 그 Explicit 인증서의 신뢰도 결국 implicit 키에 기대게 되어서 비용은 explicit 만큼 내면서 얻는 보증은 implicit 수준에 머무는 셈이라 설계상 의미가 없어서 그런 것 같음.
- 추가적으로 편의상 모두 Explicit 이거나, 아래만 Implicit 인증서로 제약을 둔게 아닐까 싶네요
- 주의할 점
- Implicit 인증서가 연속되면 확정이 마지막 서명 검증까지 미뤄진다.
- 이때 검증이 실패하면 체인의 어느 단계가 잘못되었는지 구분할 수 없다. (모든 재구성 값이 하나의 검증으로 묶여 있으므로)
- 반면 Explicit 체인은 단계마다 서명을 검증하므로 실패 지점을 알 수 있다.
인증서 체인 내 권한 및 유효 범위 정합성
- 하위 인증서의 PSID, SSP 권한, 지역, 기간은 issuer가 허용한 버무이 안에 있어야 함
- PSID, SSP 권한
- issuer의 certificate issuance permissions가 하위 인증서의 application permissions를 허용 CA -> CA에서는 하위의 certIssuePermissions
- 지역
- issuer 지역이 하위 인증서 지역과 같거나 포함
- 기간
- 시작 : issuer가 하위보다 같거나 이전
- 만료 : issuer가 하위보다 같거나 이후
인증서 검증 결과
- SSME는 인증서와 그 검증 상태를 함께 저장, 관리하고 SDS는 SPDU를 서명, 검증할 때 이 상태를 참조함
- SSME에 추가
- 미리 검증했다면 Verified = true로 추가
- 검증, 상태 갱신
- 검증 상태 관리
- 여기까지가 SSME
- SDS가 SPDU를 처리할 때 SSME의 인증서 검증 상태를 참조
- 보낼 떄 : 내 인증서와 개인키로 SPDU에 서명
- 받을 때 : 상대 인증서와 그 체인으로 서명, 유효성 검증
5. 부록: ASN.1 module IEEE1609Dot2
- 위 개념들이 실제 메시지에서 어떤 구조체로 표현되는지 정리한 레퍼런스
Data Elements
Ieee1609Dot2Data
- protocolVersion Uint8
- 현재 프로토콜 버전 (기본 : version 3)
- content Ieee1609Dot2Content
1
2
3
4
| Ieee1609Dot2Data ::= SEQUENCE {
protocolVersion Uint8(3),
content Ieee1609Dot2Content
}
|
IEEE1609Dot2Content
- unsecuredData Opaque
- 해당 콘텐츠가 SDS 외부에서 사용될 OCTET STRING임을 나타냅니다.
- signedData SignedData
- 이는 해당 콘텐츠가 이 표준에 따라 서명되었음을 나타냅니다.
- encryptedData EncryptedData
- 이 마크는 해당 콘텐츠가 이 표준에 따라 암호화되었음을 나타냅니다.
- signedCertificateRequest Opaque
- 해당 콘텐츠가 IEEE 1609.2 인증서로 서명되었거나 자체 서명된 인증서 요청임을 나타냅니다.
- signedX509CertificateRequest Opaque
- 이는 해당 콘텐츠가 ITU-T X.509 인증서로 서명된 인증서 요청임을 나타냅니다.
1
2
3
4
5
6
7
8
9
| Ieee1609Dot2Content ::= CHOICE {
unsecuredData Opaque,
signedData SignedData,
encryptedData EncryptedData,
signedCertificateRequest Opaque,
...,
signedX509CertificateRequest Opaque
}
|
SignedData
- hashId HashAlgorithm
- 서명 및 검증을 위해 메시지의 해시를 생성하는 데 사용될 해시 알고리즘을 나타냅니다.
- tbsData ToBeSignedData
- 서명의 입력값으로 해시 처리된 데이터가 포함되어 있습니다.
- signer SignerIdentifier
- 데이터에 서명하는 데 사용되는 키링 자료와 해시 알고리즘을 결정합니다.
- signature Signature
- 자기 자신의 디지털 서명을 포함한다.
- 서명 입력 해시 =
Hash(tbsData의 정규화된 COER 인코딩) || Hash(서명자 식별 입력) - signer가 self인 경우 : 서명자 식별 입력은 빈 문자열
- signer가 certificate 또는 digest인 경우
- 서명자 식별 입력은 서명자 인증서의 COER 인코딩
1
2
3
4
5
6
7
| SignedData ::= SEQUENCE {
hashId HashAlgorithm,
tbsData ToBeSignedData,
signer SignerIdentifier,
signature Signature
}
|
ToBeSignedData
- payload SignedDataPayload
- SDS를 호출하는 주체가 제공하는 데이터가 포함되어 있음
- headerInfo HeaderInfo
1
2
3
4
| ToBeSignedData ::= SEQUENCE {
payload SignedDataPayload,
headerInfo HeaderInfo
}
|
SignedDataPayload
- data Ieee1609Dot2Data OPTIONAL
- 해당 구조체 내에서 명시적으로 전달되는 데이터를 포함함
- extDataHash HashedData OPTIONAL
- 이 구조체 내에서 명시적으로 전송되지는 않지만, 구조체 작성자가 이를 서명과 암호학적으로 연결하고자 하는 데이터의 해시를 포함합니다.
- omitted NULL OPTIONAL
- 이는 서명의 해시 계산에 포함될 외부 데이터가 있음을 나타냅니다.
1
2
3
4
5
6
7
8
9
| SignedDataPayload ::= SEQUENCE {
data Ieee1609Dot2Data OPTIONAL,
extDataHash HashedData OPTIONAL,
...,
omitted NULL OPTIONAL
} (WITH COMPONENTS {..., data PRESENT} |
WITH COMPONENTS {..., extDataHash PRESENT} |
WITH COMPONENTS {..., omitted PRESENT})
|
HashedData
- sha256HashedData HashedId32
- SHA-256으로 해시 처리된 데이터를 나타냅니다.
- sha384HashedData HashedId48
- SHA-384로 해시 처리된 데이터임을 나타냅니다.
- sm3HashedData HashedId32
1
2
3
4
5
6
| HashedData::= CHOICE {
sha256HashedData HashedId32,
...,
sha384HashedData HashedId48,
sm3HashedData HashedId32
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| HeaderInfo ::= SEQUENCE {
psid Psid,
generationTime Time64 OPTIONAL,
expiryTime Time64 OPTIONAL,
generationLocation ThreeDLocation OPTIONAL,
p2pcdLearningRequest HashedId3 OPTIONAL,
missingCrlIdentifier MissingCrlIdentifier OPTIONAL,
encryptionKey EncryptionKey OPTIONAL,
...,
inlineP2pcdRequest SequenceOfHashedId3 OPTIONAL,
requestedCertificate Certificate OPTIONAL,
pduFunctionalType PduFunctionalType OPTIONAL,
contributedExtensions ContributedExtensionBlocks OPTIONAL
}
|
MissingCrlIdentifier
1
2
3
4
5
| MissingCrlIdentifier ::= SEQUENCE {
cracaId HashedId3,
crlSeries CrlSeries,
...
}
|
PduFunctionalType
- SPDU를 소비할 주체가 애플리케이션 프로세스가 아닌 보안 지원 서비스일 때, 그 기능 주체를 식별함 (ISO 21177)
- 1 : tlsHandshake
- 2 : iso21177ExtendedAuth
- 3 : iso21177SessionExtension
1
2
3
4
5
| PduFunctionalType ::= INTEGER (0..255)
tlsHandshake PduFunctionalType ::= 1
iso21177ExtendedAuth PduFunctionalType ::= 2
iso21177SessionExtension PduFunctionalType ::= 3
|
ContributedExtensionBlocks
- ContributedExtensionBlock의 목록 (1개 이상)
1
2
| ContributedExtensionBlocks ::= SEQUENCE (SIZE(1..MAX)) OF
ContributedExtensionBlock
|
ContributedExtensionBlock
1
2
3
4
5
6
7
8
9
| ContributedExtensionBlock ::= SEQUENCE {
contributorId IEEE1609DOT2-HEADERINFO-CONTRIBUTED-EXTENSION.&id({
Ieee1609Dot2HeaderInfoContributedExtensions
}),
extns SEQUENCE (SIZE(1..MAX)) OF
IEEE1609DOT2-HEADERINFO-CONTRIBUTED-EXTENSION.&Extn({
Ieee1609Dot2HeaderInfoContributedExtensions
}{@.contributorId})
}
|
- 확장 블록을 정의하기 위한 템플릿 역할을 하는 Information Object Class
- &id : 기여 조직 ID (HeaderInfoContributorId)
- &Extn : 확장 내용 타입
1
2
3
4
| IEEE1609DOT2-HEADERINFO-CONTRIBUTED-EXTENSION ::= CLASS {
&id HeaderInfoContributorId UNIQUE,
&Extn
} WITH SYNTAX {&Extn IDENTIFIED BY &id}
|
- 정의된 확장 타입과 기여 조직 ID를 연결하는 Information Object Set
- Ieee1609ContributedHeaderInfoExtension (IEEE 1609)
- EtsiOriginatingHeaderInfoExtension (ETSI)
1
2
3
4
5
6
7
8
| Ieee1609Dot2HeaderInfoContributedExtensions
IEEE1609DOT2-HEADERINFO-CONTRIBUTED-EXTENSION ::= {
{Ieee1609ContributedHeaderInfoExtension IDENTIFIED BY
ieee1609HeaderInfoContributorId} |
{EtsiOriginatingHeaderInfoExtension IDENTIFIED BY
etsiHeaderInfoContributorId},
...
}
|
- HeaderInfo 확장을 기여한 조직을 식별하는 정수
- 1 : IEEE 1609
- 2 : ETSI TC ITS
1
2
3
4
| HeaderInfoContributorId ::= INTEGER (0..255)
ieee1609HeaderInfoContributorId HeaderInfoContributorId ::= 1
etsiHeaderInfoContributorId HeaderInfoContributorId ::= 2
|
SignerIdentifier
1
2
3
4
5
6
| SignerIdentifier ::= CHOICE {
digest HashedId8,
certificate SequenceOfCertificate,
self NULL,
...
}
|
Countersignature
- 이미 서명된 SPDU 위에 추가로 서명(카운터 서명)할 때 사용하는 Ieee1609Dot2Data의 프로파일
- payload에는 data 없이 extDataHash(기존 SPDU의 해시)만 포함함
- headerInfo에는 generationTime만 필수이고, expiryTime/generationLocation 등은 포함하지 않음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| Countersignature ::= Ieee1609Dot2Data (WITH COMPONENTS {...,
content (WITH COMPONENTS {...,
signedData (WITH COMPONENTS {...,
tbsData (WITH COMPONENTS {...,
payload (WITH COMPONENTS {...,
data ABSENT,
extDataHash PRESENT
}),
headerInfo(WITH COMPONENTS {...,
generationTime PRESENT,
expiryTime ABSENT,
generationLocation ABSENT,
p2pcdLearningRequest ABSENT,
missingCrlIdentifier ABSENT,
encryptionKey ABSENT
})
})
})
})
})
|
EncryptedData
1
2
3
4
| EncryptedData ::= SEQUENCE {
recipients SequenceOfRecipientInfo,
ciphertext SymmetricCiphertext
}
|
RecipientInfo
1
2
3
4
5
6
7
| RecipientInfo ::= CHOICE {
pskRecipInfo PreSharedKeyRecipientInfo,
symmRecipInfo SymmRecipientInfo,
certRecipInfo PKRecipientInfo,
signedDataRecipInfo PKRecipientInfo,
rekRecipInfo PKRecipientInfo
}
|
SequenceOfRecipientInfo
1
| SequenceOfRecipientInfo ::= SEQUENCE OF RecipientInfo
|
PreSharedKeyRecipientInfo
- SymmetricCiphertext를 직접 복호화할 수 있는 대칭키를 가리킴
- 해당 대칭키를 담은 SymmetricEncryptionKey의 COER 인코딩 해시 하위 8바이트
1
| PreSharedKeyRecipientInfo ::= HashedId8
|
SymmRecipientInfo
- recipientId HashedId8
- DEK를 복호화할 수 있는 대칭키(키 암호화 키)의 해시
- encKey SymmetricCiphertext
1
2
3
4
| SymmRecipientInfo ::= SEQUENCE {
recipientId HashedId8,
encKey SymmetricCiphertext
}
|
PKRecipientInfo
- recipientId HashedId8
- 암호화 공개키를 담고 있는 컨테이너의 해시
- certRecipInfo : 인증서의 HashedId8
- signedDataRecipInfo : 암호화 키를 포함한 signedData 타입 Ieee1609Dot2Data의 HashedId8
- rekRecipInfo : 응답 암호화 키를 담은 PublicEncryptionKey의 HashedId8
- encKey EncryptedDataEncryptionKey
1
2
3
4
| PKRecipientInfo ::= SEQUENCE {
recipientId HashedId8,
encKey EncryptedDataEncryptionKey
}
|
EncryptedDataEncryptionKey
공개키 방식으로 암호화된 DEK
- eciesNistP256 EciesP256EncryptedKey
- NIST P-256 곡선 기반 ECIES로 암호화됨
- eciesBrainpoolP256r1 EciesP256EncryptedKey
- Brainpool P256r1 곡선 기반 ECIES로 암호화됨
- ecencSm2256 EcencP256EncryptedKey
1
2
3
4
5
6
| EncryptedDataEncryptionKey ::= CHOICE {
eciesNistP256 EciesP256EncryptedKey,
eciesBrainpoolP256r1 EciesP256EncryptedKey,
...,
ecencSm2256 EcencP256EncryptedKey
}
|
SymmetricCiphertext
승인된 대칭 알고리즘으로 생성된 암호문
- aes128ccm One28BitCcmCiphertext
- sm4Ccm One28BitCcmCiphertext
1
2
3
4
5
| SymmetricCiphertext ::= CHOICE {
aes128ccm One28BitCcmCiphertext,
...,
sm4Ccm One28BitCcmCiphertext
}
|
One28BitCcmCiphertext
- 128비트 블록 대칭 알고리즘의 CCM 모드 암호문
- MAC이 포함되어 평문보다 16바이트 길다
- 복호화 결과는 COER 인코딩된 Ieee1609Dot2Data 또는 16바이트 대칭키
- nonce OCTET STRING (SIZE (12))
- ccmCiphertext Opaque
1
2
3
4
| One28BitCcmCiphertext ::= SEQUENCE {
nonce OCTET STRING (SIZE (12)),
ccmCiphertext Opaque
}
|
Aes128CcmCiphertext
1
| Aes128CcmCiphertext ::= One28BitCcmCiphertext
|
TestCertificate
- implicit / explicit 인증서 전송을 위한 CertificateBase의 프로파일
1
| TestCertificate ::= Certificate
|
SequenceOfCertificate
1
| SequenceOfCertificate ::= SEQUENCE OF Certificate
|
CertificateBase
- version Uint8(3)
- type CertificateType
- implicit 인증서인지 explicit 인증서인지 나타냄
- issuer IssuerIdentifier
- toBeSigned ToBeSignedCertificate
- 인증서 내용
- explicit 인증서는 서명 생성/검증, implicit 인증서는 공개키 복원 시 해시 입력값으로 사용됨
- signature Signature OPTIONAL
- explicit 인증서에만 포함됨
- issuer가 toBeSigned의 해시에 대해 계산한 서명
1
2
3
4
5
6
7
| CertificateBase ::= SEQUENCE {
version Uint8(3),
type CertificateType,
issuer IssuerIdentifier,
toBeSigned ToBeSignedCertificate,
signature Signature OPTIONAL
}
|
CertificateType
- 인증서가 explicit인지 implicit인지 나타냄
1
2
3
4
5
| CertificateType ::= ENUMERATED {
explicit,
implicit,
...
}
|
ImplicitCertificate
- implicit 인증서 프로파일
- type은 implicit
- verifyKeyIndicator는 reconstructionValue
- signature 없음
- 서명 검증용 공개 키 대신, 공개 키 재구성에 필요한 값이 들어 있는 인증서
1
2
3
4
5
6
7
| ImplicitCertificate ::= CertificateBase (WITH COMPONENTS {...,
type(implicit),
toBeSigned(WITH COMPONENTS {...,
verifyKeyIndicator(WITH COMPONENTS {reconstructionValue})
}),
signature ABSENT
})
|
ExplicitCertificate
- explicit 인증서 프로파일
- type은 explicit
- verifyKeyIndicator는 verificationKey
- signature 필수
- 인증서 발급자의 서명, 인증서 보유자의 서명 검증에 사용되는 공개 키가 포함되어 있는 인증서
1
2
3
4
5
6
7
| ExplicitCertificate ::= CertificateBase (WITH COMPONENTS {...,
type(explicit),
toBeSigned (WITH COMPONENTS {...,
verifyKeyIndicator(WITH COMPONENTS {verificationKey})
}),
signature PRESENT
})
|
IssuerIdentifier
1
2
3
4
5
6
7
| IssuerIdentifier ::= CHOICE {
sha256AndDigest HashedId8,
self HashAlgorithm,
...,
sha384AndDigest HashedId8,
sm3AndDigest HashedId8
}
|
ToBeSignedCertificate
- 인증서 해시는
Hash(Data input) || Hash(Signer identifier input) 으로 계산함- Data input : 정규화된 toBeSigned의 COER 인코딩
- Signer identifier input : issuer가 self면 빈 문자열, 아니면 발급자 인증서의 COER 인코딩
- id CertificateId
- cracaId HashedId3
- 이 인증서가 포함될 수 있는 CRL을 담당하는 CRACA의 HashedId3
- crlSeries CrlSeries
- validityPeriod ValidityPeriod
- region GeographicRegion OPTIONAL
- 인증서 유효 지역
- 생략 시 자체 서명 인증서면 전 세계, 아니면 발급자 인증서와 동일
- assuranceLevel SubjectAssurance OPTIONAL
- appPermissions SequenceOfPsidSsp OPTIONAL
- 이 인증서로 애플리케이션 데이터에 서명할 수 있는 권한 (PSID별 최대 1개 항목)
- certIssuePermissions SequenceOfPsidGroupPermissions OPTIONAL
- 이 인증서로 다른 인증서를 발급(서명)할 수 있는 권한
- certRequestPermissions SequenceOfPsidGroupPermissions OPTIONAL
- 인증서 소유자가 자신의 인증서에 요청할 수 있는 권한
- canRequestRollover NULL OPTIONAL
- 동일 권한의 다른 인증서 요청에 서명할 수 있음을 나타냄 (향후 사용 목적)
- encryptionKey PublicEncryptionKey OPTIONAL
- 인증서 소유자가 개인키를 보유한 암호화용 공개키
- verifyKeyIndicator VerificationKeyIndicator
- 이 인증서로 서명된 데이터를 검증할 공개키(또는 복원 값)
- flags BIT STRING {usesCubk (0)} (SIZE (8)) OPTIONAL
- 추가 속성 플래그, usesCubk는 compact unified butterfly key 응답 지원 여부
- appExtensions SequenceOfAppExtensions
- certIssueExtensions SequenceOfCertIssueExtensions
- endEntityExtensions를 포함한 인증서를 발급할 수 있는 추가 권한
- certRequestExtension SequenceOfCertRequestExtensions
- appPermissions, certIssuePermissions, certRequestPermissions 중 최소 하나는 존재해야 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| ToBeSignedCertificate ::= SEQUENCE {
id CertificateId,
cracaId HashedId3,
crlSeries CrlSeries,
validityPeriod ValidityPeriod,
region GeographicRegion OPTIONAL,
assuranceLevel SubjectAssurance OPTIONAL,
appPermissions SequenceOfPsidSsp OPTIONAL,
certIssuePermissions SequenceOfPsidGroupPermissions OPTIONAL,
certRequestPermissions SequenceOfPsidGroupPermissions OPTIONAL,
canRequestRollover NULL OPTIONAL,
encryptionKey PublicEncryptionKey OPTIONAL,
verifyKeyIndicator VerificationKeyIndicator,
...,
flags BIT STRING {usesCubk (0)} (SIZE (8)) OPTIONAL,
appExtensions SequenceOfAppExtensions,
certIssueExtensions SequenceOfCertIssueExtensions,
certRequestExtension SequenceOfCertRequestExtensions
}
(WITH COMPONENTS { ..., appPermissions PRESENT} |
WITH COMPONENTS { ..., certIssuePermissions PRESENT} |
WITH COMPONENTS { ..., certRequestPermissions PRESENT})
|
CertificateId
- linkageData LinkageData
- linkage 기반 CRL에서 인증서 폐기 여부 확인에 사용함
- name Hostname
- 익명이 아닌 인증서에서 소유자를 식별하는 사람이 읽을 수 있는 이름
- binaryId OCTET STRING(SIZE(1..64))
- none NULL
1
2
3
4
5
6
7
| CertificateId ::= CHOICE {
linkageData LinkageData,
name Hostname,
binaryId OCTET STRING(SIZE(1..64)),
none NULL,
...
}
|
LinkageData
1
2
3
4
5
| LinkageData ::= SEQUENCE {
iCert IValue,
linkage-value LinkageValue,
group-linkage-value GroupLinkageValue OPTIONAL
}
|
PsidGroupPermissions
1
2
3
4
5
6
| PsidGroupPermissions ::= SEQUENCE {
subjectPermissions SubjectPermissions,
minChainLength INTEGER DEFAULT 1,
chainLengthRange INTEGER DEFAULT 0,
eeType EndEntityType DEFAULT {app}
}
|
SequenceOfPsidGroupPermissions
1
| SequenceOfPsidGroupPermissions ::= SEQUENCE OF PsidGroupPermissions
|
SubjectPermissions
- explicit SequenceOfPsidSspRange
- 명시된 PSID와 SSP 범위에 대해 권한을 부여함
- all NULL
- 같은 필드 내 다른 항목에 명시되지 않은 모든 PSID에 대해 권한을 부여함
1
2
3
4
5
| SubjectPermissions ::= CHOICE {
explicit SequenceOfPsidSspRange,
all NULL,
...
}
|
VerificationKeyIndicator
- verificationKey PublicVerificationKey
- explicit 인증서에 포함되며, 서명 검증용 공개키
- reconstructionValue EccP256CurvePoint
- implicit 인증서에 포함되며, 공개키를 복원하는 데 사용하는 값 (SEC 4)
1
2
3
4
5
| VerificationKeyIndicator ::= CHOICE {
verificationKey PublicVerificationKey,
reconstructionValue EccP256CurvePoint,
...
}
|
- Ieee1609ContributedHeaderInfoExtension을 식별하는 정수
- 1 : p2pcd8ByteLearningRequestId
1
2
3
| Ieee1609HeaderInfoExtensionId ::= ExtId
p2pcd8ByteLearningRequestId Ieee1609HeaderInfoExtensionId ::= 1
|
- IEEE 1609 HeaderInfo 확장과 확장 ID를 연결하는 Information Object Set
- p2pcd8ByteLearningRequestId → HashedId8
1
2
3
4
| Ieee1609HeaderInfoExtensions EXT-TYPE ::= {
{HashedId8 IDENTIFIED BY p2pcd8ByteLearningRequestId},
...
}
|
SequenceOfAppExtensions
- 인증서 소유자에게 적용되는 AppExtension 목록
1
| SequenceOfAppExtensions ::= SEQUENCE (SIZE(1..MAX)) OF AppExtension
|
AppExtension
1
2
3
4
| AppExtension ::= SEQUENCE {
id CERT-EXT-TYPE.&id({SetCertExtensions}),
content CERT-EXT-TYPE.&App({SetCertExtensions}{@.id})
}
|
SequenceOfCertIssueExtensions
- 인증서 소유자에게 적용되는 CertIssueExtension 목록
1
2
| SequenceOfCertIssueExtensions ::=
SEQUENCE (SIZE(1..MAX)) OF CertIssueExtension
|
CertIssueExtension
- id
- permissions
- specific : 발급 가능한 확장 값을 명시함
- all : 해당 확장의 모든 값을 발급할 수 있음
1
2
3
4
5
6
7
| CertIssueExtension ::= SEQUENCE {
id CERT-EXT-TYPE.&id({SetCertExtensions}),
permissions CHOICE {
specific CERT-EXT-TYPE.&Issue({SetCertExtensions}{@.id}),
all NULL
}
}
|
SequenceOfCertRequestExtensions
- 인증서 소유자에게 적용되는 CertRequestExtension 목록
1
| SequenceOfCertRequestExtensions ::= SEQUENCE (SIZE(1..MAX)) OF CertRequestExtension
|
CertRequestExtension
- id
- permissions
- content : 요청 가능한 확장 값을 명시함
- all : 해당 확장의 모든 값을 요청할 수 있음
1
2
3
4
5
6
7
| CertRequestExtension ::= SEQUENCE {
id CERT-EXT-TYPE.&id({SetCertExtensions}),
permissions CHOICE {
content CERT-EXT-TYPE.&Req({SetCertExtensions}{@.id}),
all NULL
}
}
|
OperatingOrganizationId
- 운영 조직을 식별하는 AppExtension (OID)
- SPDU에서 얻은 OID가 이 필드의 OID와 같으면 일치하는 것으로 봄
- CertIssueExtension과의 일관성 조건은 없으며, 어떤 CA든 발급 가능
1
2
3
4
5
6
7
8
9
10
| OperatingOrganizationId ::= OBJECT IDENTIFIER
certExtId-OperatingOrganization ExtId ::= 1
instanceOperatingOrganizationCertExtensions CERT-EXT-TYPE ::= {
ID certExtId-OperatingOrganization
APP OperatingOrganizationId
ISSUE NULL
REQUEST NULL
}
|
SetCertExtensions
- AppExtension, CertIssueExtension, CertRequestExtension 타입을 모아둔 Information Object Set
- 현재 버전에서는 instanceOperatingOrganizationCertExtensions 하나만 있음
1
2
3
4
| SetCertExtensions CERT-EXT-TYPE ::= {
instanceOperatingOrganizationCertExtensions,
...
}
|