# 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를 사용할 수 있습니다. image alt text

# 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를 참고하십시오.