# VCP Message
VCP는 Verifiable Crednetial - Verifiable Presentation 의 약자 입니다.
Credential을 발급하고 presentation을 검증하기 위해서 entity간에 message가 전송이 되어야 합니다. 이렇게 entity간에 교환되는 message의 규격을 VCP Message라고 합니다.
# VCP Message Overview
VCP message는 아래 그림과 같은 구조를 가집니다. Message 교환이 시작되는 시점의 meessage는 unprotected입니다.
최초 message 이후 부터는 암호화된 protected message를 사용할 수 있습니다.
# Unprotected Message
암호화 되지 않은 message입니다.
- type: DID_INIT, DID_AUTH, CREDENTIAL등 현재 message의 타입을 선언합니다.
- message: 암호화 되지않은 JWT (opens new window) message입니다.
- param: (optional) Credential message인 경우 credential의 상세정보를 가집니다.
# Protected Message
암호화된 message입니다.
- type: DID_INIT, DID_AUTH, CREDENTIAL등 현재 message의 타입을 선언합니다.
- protected: 암호회된 JWE (opens new window) message입니다.
- JWE Header: JWE header입니다.
- EncryptKey: 암호화에 사용되는 키 입니다.
- IV: Initial-Vector
- CipherText: Unprotected message에서 설명한 JWT 여기에 위치하게 됩니다.
- AuthTag: Auth-Tag
# VCP Message Description
# DID Init
* Typed Message
{
"type": "did_init",
"message": "[JWT Header].[JWT Payload].[Signature]" // base64url
}
* JWT Header
{
"alg": "ES256K",
"kid": "did:icon:01:000...1#key-1"
}
* JWT Payload
{
"version" : "2.0",
"type" : [ "DID_INIT" ],
"iss" : "did:icon:01:000...2",
"iat" : 1553582482,
"nonce": "b0f184df3f4e92ea9496d9a0aad259ae",
"publicKey": { // issuer의 EphemeralPublicKey
"kid": "issuerKey-1", // issuer가 사용할 ECDHKey의 식별ID
"epk": { // issuer의 ECDHKey
"kty": "EC",
"crv": "P-256K",
"x": "...", // base64url
"y": "..." // base64url
}
}
}
# DID auth
* Typed Message
{
"type": "did_auth",
"protected": "[JWEHeader].[EncryptedKey].[IV].[CipherText].[AuthTag]"// base64url
}
* JWE header // Holder의 ECDHKey 정보
{
"alg": "ECDH-ES",
"kid": "holderKey-1", // holder의 ECDHKey 식별자
"enc": "A128GCM",
"epk": { // holder의 ECDHKey
"kty": "EC",
"crv": "P-256K",
"x": "...", // base64url
"y": "..." // base64url
}
}
* EncryptedKey // Encrypted-Symm-Key
* IV // Initial-Vector
* CipherText // Encrypted-ProtocolMessage
* AuthTag // Auth-Tag
// 암호화 된 CipherText의 내용은 아래와 같습니다.
* ProtocolMessage
{
"message": "[JWT Header].[JWT Payload].[Siganture]" // Credential JWT token
}
// ProtocolMessage의 message(JWT token)는 아래와 같이 header, payload, Signature로 구성됩니다.
* JWT header
{
"alg": "ES256K",
"kid": "did:icon:01:0000...2#holderKey-1"
}
* JWT Payload
{
"version" : "2.0",
"type" : [ "DID_AUTH" ],
"iss" : "did:icon:01:000...3", // holder의 DID
"aud" : "did:icon:01:000...2", // issuer의 DID
"iat" : 1553582498,
"nonce": "b0f184df3f4e92ea9496d9a0aad259ae"
}
* Signature
# Request Credential
* Typed Message
{
"type": "request_credential",
"protected": "[JWEHeader].[EncryptedKey].[IV].[CipherText].[AuthTag]" // base64url
}
* JWE header // Issuer의 ECDHKey 정보
{
"alg": "ECDH-ES",
"kid": "holderKey-1", // holder의 ECDHKey 식별자
"enc": "A128GCM",
"epk": {
"kty": "EC",
"crv": "P-256K",
"x": "...", // base64url
"y": "..." // base64url
}
}
* EncryptedKey // Encrypted-Symm-Key
* IV // Initial-Vector
* CipherText // Encrypted-ProtocolMessage
* AuthTag // Auth-Tag
// CiperText 내용.
* ProtocolMessage
{
"message": "[JWT Header].[JWT Payload].[Siganture]" // Request Credential
}
* JWT header
{
"alg": "ES256K",
"kid": "did:icon:01:0000...2#issuerKey-1"
}
* JWT Payload
{
"version" : "2.0",
"type" : ["REQ_CREDENTIAL"],
"iss" : "did:icon:03:a4b1234fsweqwexdb6c8bab94a38df530d225e840b1211d", // Holder's DID
"aud" : "did:icon:03:c3bb75caef41476db6c8bab94a38df530d225e840bf5448c", // Issuer's DID
"iat" : 1578445405,
"nonce" : "b0f184df3f4e92ea9496d9a0aad259ae",
"vcr": {
"@context": [
"http://vc.zzeung.kr/credentials/v1.json",
"http://vc.zzeung.kr/credentials/mobile_authentication/kor/v1.json"
],
"id": "https://www.zzeung.id/vcr/phonevc/123623",
"@type": [
"CredentialRequest",
"MobileAuthenticationKorCredential"
],
"requestClaim": {
"name": "홍길순",
"birthDate": "2000-01-01",
"gender": "female",
"telco": "SKT",
"phoneNumber": "01031142962",
"connectingInformation": "0000000000000000000000000000000000000000",
"citizenship": true
}
}
}
* message - signature
# Credential
Issuer가 발급하는 Credential은 아래와 같이 구성이 됩니다.
* Typed Message
{
"type": "response_credential",
"protected": "[JWEHeader].[EncryptedKey].[IV].[CipherText].[AuthTag]"// base64url
}
* JWE header // Issuer의 ECDHKey 정보
{
"alg": "ECDH-ES",
"kid": "issuerKey-1", // Issuer ECDHKey 식별자
"enc": "A128GCM",
"epk": {
"kty": "EC",
"crv": "P-256K",
"x": "...", // base64url
"y": "..." // base64url
}
}
* EncryptedKey // Encrypted-Symm-Key
* IV // Initial-Vector
* CipherText // Encrypted-ProtocolMessage
* AuthTag // Auth-Tag
// 암호화 된 CipherText의 내용은 아래와 같습니다.
* ProtocolMessage
{
"message": "[JWT Header].[JWT Payload].[Siganture]", // Credential JWT token
"param": "[Param]" // Non-hashed claim value and claim nonce
}
// ProtocolMessage의 message(JWT token)는 아래와 같이 header, payload, Signature로 구성됩니다.
* message - header
{
"alg": "ES256K",
"kid": "did:icon:01:0000...2#issuerKey-1"
}
* message - payload
// payload에서 "vc": { } 의 내용들은 JSON-LD 입니다.
{
"version": "2.0",
"type": ["CREDENTIAL"],
"iss": "did:icon:03:c3bb75caef41476db6c8bab94a38df530d225e840bf5448c",
"sub": "did:icon:03:a4b1234fsweqwexdb6c8bab94a38df530d225e840b1211d",
"iat": 1578445403,
"exp": 1578531803,
"vc": {
"@context": [
"http://vc.zzeung.kr/credentials/v1.json",
"http://vc.zzeung.kr/credentials/mobile_authentication/kor/v1.json"
],
"id": "https://myid.id/credential/example/phone/vc/0000001",
"type": ["VerifiableCredential","MobileAuthenticationKorCredential"],
"cryptoType": "hash",
"cryptoAlgorithm": "SHA-256",
"credentialSubject": {
"id": "did:icon:03:a4b1234fsweqwexdb6c8bab94a38df530d225e840b1211d",
"name": "a3445c2236841af6bf25d0c3b9196f968082de2ba7e1657001e1dd4dbf8d894",
"birthDate": "cc183c2236841af6bf25d0c3b9196f968082de2ba7e1657001e1dd4dbf8",
"gender": "5583c2236841af6bf25d0c3b9196f968082de2ba7e1657001e1dd4dbf8d894",
"telco": "108a3c2236841af6bf25d0c3b9196f968082de2ba7e1657001e1dd4dbf8d894",
"phoneNumber": "123383c2236841af6bf25d0c3b9196f968082de2ba7e1657001e1dd4d",
"connectingInformation": "ff383c2236841af6bf25d0c3b9196f968082de2ba7e165700",
"citizenship": "ff383c2236841af6bf25d0c3b9196f968082de2ba7e1657001e1dd4"
},
"refreshService": {
"id": "https://vc.example.com/refresh_service/",
"type": "ManualRefreshService"
}
},
"jti": "885c592008a5b95a8e348e56b92a2361",
"nonce": "b0f184df3f4e92ea9496d9a0aad259ae"
}
* message - signature
// ProtocolMessage의 param은 아래와 같습니다.
// param은 JSON-LD 입니다.
* param
{
"@context": [
"http://vc.zzeung.kr/credentials/v1.json",
"http://vc.zzeung.kr/credentials/mobile_authentication/kor/v1.json"
],
"type": ["CredentialParam", "MobileAuthenticationKorCredential"],
"credentialParam": {
"claim": {
"name": {
"claimValue": "홍길순",
"salt": "a1341c4b0cbff6bee9118da10d6e85a5"
},
"birthDate": {
"claimValue": "2000-01-01",
"salt": "65341c4b0cbff6bee9118da10d6e85a5"
},
"gender": {
"claimValue": "female",
"salt": "12341c4b0cbff6bee9118da10d6e85a5",
"displayValue": "여성"
},
"telco": {
"claimValue": "SKT",
"salt": "91341c4b0cbff6bee9118da10d6e85a5"
},
"phoneNumber": {
"claimValue": "01031142962",
"salt": "e2341c4b0cbff6bee9118da10d6e85a5"
"displayValue": "010-3114-2962"
},
"connectingInformation": {
"claimValue": "0000000000000000000000000000000000000000",
"salt": "ff341c4b0cbff6bee9118da10d6e85a5"
},
"citizenship": {
"claimValue": true,
"salt": "f2341c4b0cbff6bee9118da10d6e85a5",
"displayValue": "내국인"
}
},
"displayLayout": ["name", "birthDate", "gender", "telco", "phoneNumber", "citizenship"],
"proofType": "hash",
"hashAlgorithm": "SHA-256"
}
}
# Request Presentation
* Typed Message
{
"type": "request_presentation",
"message": "[JWT Header].[JWT Payload].[Signature]" // base64url
}
* JWT Header
{
"alg": "ES356K-R",
"kid": "did:icon:01:c07bbcf24b7d9c7a1202e8ed0a64d17eee956aa48561bc93#key-1"
}
* JWT Payload
{
"version" : "2.0",
"type" : ["REQ_PRESENTATION"],
"iss" : "did:icon:01:c07bbcf24b7d9c7a1202e8ed0a64d17eee956aa48561bc93",
"aud" : "did:icon:01:b7d31981bfe8600b44e1be05af9bed1a60458d23e827c6c5",
"iat" : 1578445405,
"nonce" : "095e7f77c8f12fb304d120bf8d15c582",
"publicKey": { "kid": "1c3df4fc51cd2d1c7c481bf1948b80e7",
"epk": { "kty": "EC",
"crv": "P-256K",
"x": "JTj3fA7hRhhEkSLsnxxJ3kKrRagoR", "y": "Y-RSrWvIJVfepboiaYbKlnIFcNz68Y_A" }
},
"vpr": {
"@context": ["https://vc.zzeung.kr/credentials/v1.json"],
"id": "https://www.shinhan.com/vpr/mobileAuthenticationKorCredential/123623",
"@type": ["PresentationRequest"],
"presentationRequest": {
"purpose": "fill-in",
"purposeLabel": "adult authentication",
"condition": {
"@type": ["SimpleCondition"],
"conditionId": "uuid-requisite-0000-1111-2222",
"issuer": [ "did:icon:01:iconloop......", "did:icon:01:shinhan-bank....."], // optional
"@context": ["https://vc.zzeung.kr/credentials/mobile_authentication/kor/v1.json"],
"credentialType": "MobileAuthenticationKorCredential",
"property": [ "name", "gender", "telco", "phoneNumber", "connectingInformation", "birthDate" ]
}
}
}
}
JWT payload 내의 "vpr": { } 은 JSON-LD (opens new window)입니다.
"id": VPR의 ID 입니다. 이 값은 verifier가 임의의 unique한 값을 사용하면 됩니다.
"purpose": Presentation 제출의 목적입니다. 이 문구는 쯩 앱에서 사용자에게 제출의 목적으로 노출 됩니다.
"@type" : [“SimpleCondition”]: VPR의 타입 중 간단하게 하나의 제출 조건을 표현하는 타입입니다. CompoundCondition과 같이 좀 더 복잡한 제출 조건을 표현 하는 타입도 있습니다.
conditionId: Verifier가 VP를 수신했을 때 어떤 VPR에 대한 응답인지 확인 하기 위해서 사용 됩니다. Verifier가 이해할 수 있는 unique한 임의의 값으로 채워 넣으면 됩니다.
issuer: 제출받을 VC를 선택할 때 VC를 발급한 issuer를 지정합니다.
@context : Credential의 내용에 대해 정의하는 JSON-LD (opens new window) @context 파일에 대한 URL입니다.
credentialType: 제출 받을 VC의 type을 지정합니다.
property: Credential은 다수의 claim 정보를 가지고 있습니다. 그 중에 VP에서 필요로하는 claim을 서술합니다. Holder인 쯩 앱 (opens new window)은 Credential의 claim 내용 중에서 verifier가 요청하는 것만 선택적으로 전달합니다. 이 문서의 Selective Disclosure 를 참고하십시오.
# Presentation
* Typed Message
{
"type": "response_presentation",
"protected": "[JWEHeader].[EncryptedKey].[IV].[CipherText].[AuthTag]"// base64url
}
* JWE header // Holder의 ECDHKey 정보
{
"alg": "ECDH-ES",
"kid": "holderKey-1", // holder의 ECDHKey 식별자
"enc": "A128GCM",
"epk": {
"kty": "EC",
"crv": "P-256K",
"x": "...", // base64url
"y": "..." // base64url
}
}
* EncryptedKey // Encrypted-Symm-Key
* IV // Initial-Vector
* CipherText // Encrypted-ProtocolMessage
* AuthTag // Auth-Tag
// 암호화 된 CipherText의 내용은 아래와 같습니다.
* ProtocolMessage
{
"message": "[JWT Header].[JWT Payload].[Siganture]" // Credential JWT token
}
// ProtocolMessage의 message(JWT token)는 아래와 같이 header, payload, Signature로 구성됩니다.
* message - header
{
"alg": "ES256K",
"kid": "did:icon:01:0000...2#holderKey-1"
}
* message - payload
// payload에서 "verifiableCredential": { } 는 Credential Message내에 있는 "vc" 내용을 base64로 인코딩한 문자열입니다.
{
"version": "2.0",
"type": ["PRESENTATION"],
"iss": "did:icon:01:0000...2",
"sub": "did:icon:01:c07bbcf24b7d9c7a1202e8ed0a64d17eee956aa48561bc93",
"iat": 1578445403,
"nonce": "095e7f77c8f12fb304d120bf8d15c582",
"vp": {
"@context": ["http://vc.zzeung.kr/credentials/v1.json"],
"id": "https://www.iconloop.com/vp/qnfdkqkd/123623",
"type": ["PresentationResponse"],
"fulfilledCriteria": {
"conditionId": "uuid-requisite-0000-1111-2222",
"verifiableCredential": "eyJhbGciOiJFUzI1NksiLCJraWQiOiJkaWQ6aWNvbjowMToyZmRhN2Y1MTYzZWMxNDU3ZDQ3MTE2N2JhMmRlMjQ2MTZlMTBhODA3OWE0ZjFhYmYjaXNzLWtleS0xIn0….",
"verifiableCredentialParam": {
"@context": [
"http://vc.zzeung.kr/credentials/v1.json",
"http://vc.zzeung.kr/credentials/mobile_authentication/kor/v1.json"
],
"type": ["CredentialParam", "MobileAuthenticationKorCredential"],
"credentialParam": {
"claim": {
"name": {
"claimValue": "홍길순",
"salt": "a1341c4b0cbff6bee9118da10d6e85a5"
},
"birthDate": {
"claimValue": "2000-01-01",
"salt": "65341c4b0cbff6bee9118da10d6e85a5"
},
"gender": {
"claimValue": "female",
"salt": "12341c4b0cbff6bee9118da10d6e85a5",
"displayValue": "여성"
},
"telco": {
"claimValue": "SKT",
"salt": "91341c4b0cbff6bee9118da10d6e85a5"
},
"phoneNumber": {
"claimValue": "01031142962",
"salt": "e2341c4b0cbff6bee9118da10d6e85a5"
"displayValue": "010-3114-2962"
},
"connectingInformation": {
"claimValue": "0000000000000000000000000000000000000000",
"salt": "ff341c4b0cbff6bee9118da10d6e85a5"
},
"citizenship": {
"claimValue": true,
"salt": "f2341c4b0cbff6bee9118da10d6e85a5",
"displayValue": "내국인"
}
},
"displayLayout": ["name", "gender", "phoneNumber", "telco", "birthDate"],
"proofType": "hash",
"hashAlgorithm": "SHA-256"
}
}
}
}
}
* message - signature
# Request Revocation
Holder는 VC 폐기를 위해 아래와 같은 jwt를 만들어서 issuer에게 전달합니다.
* Typed Message
{
"type": "request_revocation",
"message": "[JWT Header].[JWT Payload].[Signature]" // base64url
}
* Header
{
"alg": "ES256K",
"kid": "did:icon:01:f2934a635f2b8e4d541a11010a9f8de92312b378e550551f#key1"
}
.
* Payload
{
"version": "2.0",
"type": ["REQ_REVOCATION"],
"iat": 1578031327277,
"iss": "did:icon:01:f2934a635f2b8e4d541a11010a9f8de92312b378e550551f", // Holder DID
"aud": "did:icon:01:1f04505ba01f1f80775aff9c8f9780c86d72af13af6233a2", // Issuer DID
"sig": "Obm3ekGFOoWoXb5EqLw311RdHQ8vAwtmSFFyA7WpnAstFCoPD42FklbrkMuAZ1BOcU90SdijThWtcUxIayzC8AE=" // 폐기할 VC Sig
}
.
* Signature
# Response Revocation
Issuer는 revocation 요청에 대한 응답으로 아래와 같은 jwt를 holder에게 전달합니다.
* Typed Message
{
"type": "response_revocation",
"message": "[JWT Header].[JWT Payload].[Signature]" // base64url
}
* Header
{
"alg": "ES256K",
"kid": "did:icon:01:1f04505ba01f1f80775aff9c8f9780c86d72af13af6233a2#key0"
}
.
* Payload
{
"version": "2.0",
"type": ["RES_REVOCATION"],
"iat": 1578031327277,
"iss": "did:icon:01:1f04505ba01f1f80775aff9c8f9780c86d72af13af6233a2", // Issuer DID
"aud": "did:icon:01:f2934a635f2b8e4d541a11010a9f8de92312b378e550551f", // Holder DID
// 성공
"result": true,
// 실패
"result": false,
"errorCode": "100",
"errorMessage": "Fail to verify signature"
}
.
* Signature
에러 코드는 Appendix의 Revocation Request & Revocation Result를 참고하십시오.