# Sample Source Code
예제로 사용된 전체 소스코드입니다.
package com.iconloop.myid.common;
import com.google.gson.JsonObject;
import foundation.icon.did.Credential;
import foundation.icon.did.DidService;
import foundation.icon.did.Presentation;
import foundation.icon.did.core.Algorithm;
import foundation.icon.did.core.AlgorithmProvider;
import foundation.icon.did.core.DidKeyHolder;
import foundation.icon.did.core.Keystore;
import foundation.icon.did.document.Document;
import foundation.icon.did.document.EncodeType;
import foundation.icon.did.document.PublicKeyProperty;
import foundation.icon.did.exceptions.AlgorithmException;
import foundation.icon.did.exceptions.TransactionException;
import foundation.icon.did.jwe.ECDHKey;
import foundation.icon.did.jwe.EphemeralPublicKey;
import foundation.icon.did.jwt.Jwt;
import foundation.icon.did.protocol.*;
import foundation.icon.did.protocol.jsonld.*;
import foundation.icon.icx.IconService;
import foundation.icon.icx.KeyWallet;
import foundation.icon.icx.data.Address;
import foundation.icon.icx.data.Bytes;
import foundation.icon.icx.data.TransactionResult;
import foundation.icon.icx.transport.http.HttpProvider;
import foundation.icon.myid.BaseService;
import foundation.icon.myid.CredentialService;
import foundation.icon.myid.IssuerService;
import foundation.icon.myid.VerifierService;
import foundation.icon.myid.credential.CredentialInfo;
import foundation.icon.myid.credential.CredentialInfoScoreParameter;
import foundation.icon.myid.credential.RevokeCredentialInfo;
import foundation.icon.myid.credential.RevokeCredentialInfoScoreParameter;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.security.PublicKey;
import java.util.*;
/**
* SDK Guide 문서에 사용될 소스코드
*/
public class IssuerVerifierCommonExample {
// DID와 암호화된 private key를 가지고 있는 Class
private DidKeyHolder mDidKeyHolder;
// 지갑
private KeyWallet mWallet;
// did score service
private DidService mDidService;
// vc score service
private CredentialService mVcService;
// VCP message에서 공통으로 쓰이는 nonce값
private String mNonce;
// ECDHKey of Issuer
private ECDHKey mServerECDHKey;
// MyID Issuer 서비스.
private IssuerService mIssuerService;
// MyID Verifier 서비스.
private VerifierService mVerifierService;
// MyID WAS URL. 테스트베드는 "https://iv-test.zzeung.id" 이고, 라이브는 파라메타 담당자에게 문의 하십시오.
private static final String IV_WAS_URL = "https://iv-test.zzeung.id";
// Credential을 요청하는 Holder의 DID
private String mHolderDid;
// Credential을 요청하는 Holder의 ECDH key
private ECDHKey mHolderECDHKey;
public enum NodeConnectType {
MYID_WAS, SCORE
}
private NodeConnectType NODE_CONNECT_TYPE = NodeConnectType.MYID_WAS;
// Initialize
public void initForNode() {
// nodeUrl, networkId, didScoreAddress, vcScoreAddress는 Blockchain 네트워크에 따라 변경됨.
String nodeUrl = "https://blockchain-test.zzeung.id/api/v3";
String networkId = "13057";
BigInteger nid = new BigInteger(networkId);
String didScoreAddress = "cx1d4b59ddf32c8ecc41bb17129f98093dd632e692";
String vcScoreAddress = "cxecb23969e2538cdae37a7d0c27902c077d9a2131";
IconService iconService = new IconService(new HttpProvider(nodeUrl));
mDidService = new DidService(
iconService, nid, new Address(didScoreAddress));
mVcService = new CredentialService(
iconService, nid, new Address(vcScoreAddress));
try {
mDidKeyHolder = Keystore.loadDidKeyHolder("P@assw0rd", new File("/did.json"));
} catch (Exception e) {
e.printStackTrace();
}
Algorithm algorithm = AlgorithmProvider.create(AlgorithmProvider.Type.ES256K);
mWallet = KeyWallet.load(
new Bytes(algorithm.privateKeyToByte(mDidKeyHolder.getPrivateKey()))
);
try {
mServerECDHKey = ECDHKey.generateKey(ECDHKey.CURVE_P256K);
} catch (Exception e) {
e.printStackTrace();
}
mNonce = EncodeType.HEX.encode(AlgorithmProvider.secureRandom().generateSeed(16));
}
// Initialize
public void initForMyIdServer() {
try {
mDidKeyHolder = Keystore.loadDidKeyHolder("P@assw0rd", new File("/did.json"));
} catch (Exception e) {
e.printStackTrace();
}
mVerifierService = VerifierService.create(IV_WAS_URL);
mIssuerService = IssuerService.create(IV_WAS_URL);
try {
mServerECDHKey = ECDHKey.generateKey(ECDHKey.CURVE_P256K);
} catch (Exception e) {
e.printStackTrace();
}
mNonce = EncodeType.HEX.encode(AlgorithmProvider.secureRandom().generateSeed(16));
}
/**
* Credential을 발급하기 위해 DID_INIT message를 생성
*/
public String createDidInitMessage() {
ProtocolMessage protocolMessage = null;
try {
EphemeralPublicKey publicKey = new EphemeralPublicKey.Builder()
.kid(mNonce)
.epk(mServerECDHKey)
.build();
ClaimRequest request = new ClaimRequest.DidBuilder(ClaimRequest.Type.INIT)
.nonce(mNonce)
.didKeyHolder(mDidKeyHolder)
.publicKey(publicKey)
.version("2.0")
.build();
protocolMessage = new ProtocolMessage.RequestBuilder()
.type(ProtocolType.DID_INIT)
.claimRequest(request)
.build();
} catch (Exception exception) {
exception.printStackTrace();
}
ProtocolMessage.SignResult didInitSignResult = protocolMessage.signEncrypt(mDidKeyHolder);
if (!didInitSignResult.isSuccess()) {
System.out.println("DidInit create sign fail.");
}
JsonObject didInitObject = didInitSignResult.getResult();
return didInitObject.toString();
}
public void verifyDidAuthMessage(String DID_AUTH_JWE) {
ProtocolMessage didAuthResPm = ProtocolMessage.valueOf(DID_AUTH_JWE);
String keyId = didAuthResPm.getJweKid();
if (didAuthResPm.isProtected()) {
didAuthResPm.decryptJwe(mServerECDHKey); // JWE -> JWT 복호화
}
boolean verifyResult = false;
try {
verifyResult = verifyDidAuth(didAuthResPm, mServerECDHKey, keyId, mNonce);
} catch (Exception e) {
e.printStackTrace();
}
if (verifyResult) {
mHolderDid = didAuthResPm.getClaimResponseJwt().getDid();
} else {
// Fail to verify DID_AUTH_JWE
}
}
private boolean verifyDidAuth(ProtocolMessage didAuthPm, ECDHKey issuerECDHKey, String issuerKeyId, String nonce) throws Exception {
ClaimResponse didAuthResponse = didAuthPm.getClaimResponseJwt();
mHolderECDHKey = didAuthPm.getJwe().getJweHeader().getEpk();
EphemeralPublicKey holderPublicKey = new EphemeralPublicKey.Builder()
.kid(issuerKeyId)
.epk(mHolderECDHKey)
.build();
String holderDid = didAuthResponse.getDid();
String holderKeyId = didAuthResponse.getKeyId();
Document holderDoc = null;
try {
if (NODE_CONNECT_TYPE == NodeConnectType.MYID_WAS) {
// MyID WAS로 부터 Holder DID Document 조회.
holderDoc = mIssuerService.getDid(holderDid);
} else {
// Blockchain에서 Holder DID Document 조회
holderDoc = mDidService.readDocument(holderDid);
PublicKeyProperty ppp = holderDoc.getPublicKeyProperty("xxx");
}
} catch (Exception e) {
e.printStackTrace();
}
if (holderDoc == null) {
System.out.println("DidAuth holderDoc is null");
return false;
} else if (holderDoc != null) {
// nonce 확인
String holderNonce = didAuthResponse.getJwt().getPayload().getNonce();
if (!nonce.equals(holderNonce)) {
System.out.println("Not equals nonce value");
return false;
}
PublicKeyProperty publicKeyProperty =
holderDoc.getPublicKeyProperty(holderKeyId);
if (publicKeyProperty == null || publicKeyProperty.isRevoked()) {
System.out.println("DidAuth's holderDid revoked");
return false;
} else {
PublicKey publicKey = publicKeyProperty.getPublicKey();
Jwt.VerifyResult verifyResult = didAuthResponse.verify(publicKey);
if (!verifyResult.isSuccess()) {
System.out.println(verifyResult.getFailMessage()); // verify fail
return false;
}
}
}
System.out.println("Verifying DidAuth succeeded.");
return true;
}
public String createCredential() {
// credential에 담을 claim value 예시
Map<String, Claim> claims = new LinkedHashMap<>();
claims.put("name", new Claim("홍길순"));
claims.put("gender", new Claim("female", "여성"));
claims.put("phoneNumber", new Claim("01031142962", "010-3114-2962"));
claims.put("telco", new Claim("SKT"));
claims.put("birthDate", new Claim("2000-01-01"));
claims.put("connectingInformation", new Claim("0000000000000000000000000000000000000000"));
List<String> layoutList = Arrays.asList("name", "gender", "phoneNumber", "telco", "birthDate");
DisplayLayout displayLayout = new DisplayLayout.StrBuilder().displayLayout(layoutList).build();
JsonLdParam credentialParam = new JsonLdParam.Builder()
.context(Arrays.asList("https://vc.zzeung.kr/credentials/v1.json",
"http://vc.zzeung.kr/credentials/mobile_authentication/kor/v1.json"))
.type(Arrays.asList("CredentialParam", "MobileAuthenticationKorCredential"))
.proofType("hash")
.hashAlgorithm("SHA-256")
.claim(claims)
.displayLayout(displayLayout)
.build();
String nonce = EncodeType.HEX.encode(AlgorithmProvider.secureRandom().generateSeed(16));
Credential credential = new Credential.Builder()
.didKeyHolder(mDidKeyHolder) // Issuer DID
.nonce(nonce)
.targetDid(mHolderDid) // Holder DID
.vcParam(credentialParam)
.id("https://myid.id/credential/example/phone/vc/0000001") // Credential의 ID (아무값이나 입력)
.refreshId("https://vc.example.com/refresh_service/") // 재발급 URL (optional)
.refreshType("ManualRefreshService") // 재발급 가능함을 명시(optional)
.version("2.0")
.build();
Date issued = new Date();
// 365일짜리 유효기간을 만듬.
long duration = credential.getDuration() * 365 * 1000L;
Date expiration = new Date(issued.getTime() + duration);
EphemeralPublicKey holderPublicKey = new EphemeralPublicKey.Builder()
.kid(mNonce)
.epk(mHolderECDHKey)
.build();
ProtocolMessage credentialPm = null;
try {
credentialPm = new ProtocolMessage.CredentialBuilder()
.type(ProtocolType.RESPONSE_CREDENTIAL)
.credential(credential)
.requestPublicKey(holderPublicKey) // received key from holder
.issued(issued)
.expiration(expiration)
.build();
} catch (Exception e) {
e.printStackTrace();
}
ProtocolMessage.SignResult credentialSignResult =
credentialPm.signEncrypt(mDidKeyHolder, mServerECDHKey);
JsonObject credentialObj = credentialSignResult.getResult();
if (!credentialSignResult.isSuccess()) {
System.out.println("Signing Credential failed.");
// mDidKeyHolder의 key store파일이 문제가 없는지 확인 필요.
return null;
}
// 발급할 VC를 Blockchain에 등록
boolean isRegisterVc = false;
if (NODE_CONNECT_TYPE == NodeConnectType.MYID_WAS) {
isRegisterVc = registerCredentialViaMyIDServer(credentialPm);
} else {
isRegisterVc = registerCredentialViaScore(credentialPm);
}
if(!isRegisterVc) {
// VC를 블록체인에 등록 실패함.
return null;
}
// TODO 기존에 이 사용자가 발급 받고, blockchain에 저장한 VC가 있다면 여기서 폐기 (Optional)
String oldVcSignature = ""; // DB 에서 가지고 와야 함.
if (NODE_CONNECT_TYPE == NodeConnectType.MYID_WAS) {
revokeCredentialInfoViaMyIDServer(oldVcSignature);
} else {
revokeCredentialInfoViaScore(oldVcSignature);
}
// TODO 등록한 VC를 나중에 위와같은 코드로 폐기 하기위한 ID인 VC ID (VC Signature)를 DB저장 해야함.
// TODO 아래 vcSignature를 DB에 저장하고 추 후 폐기가 필요할 때 사용해야 함.
String vcSignature = credentialPm.getJwt().getSignature();
return credentialObj.toString();
}
public String createRequestPresentationForPhoneId() {
EphemeralPublicKey verifierPublicKey = new EphemeralPublicKey.Builder()
.kid(mNonce)
.epk(mServerECDHKey)
.build();
// 제출 요청할 항목
List<String> requireProperty = Arrays.asList("name", "gender", "telco", "phoneNumber", "connectionInformation", "birthDate");
// 조건 작성
VprCondition condition = new VprCondition.SimpleBuilder() // SimpleCondition
.conditionId("uuid-requisite-0000-1111-2222") // 아무값이나 입력
.context(Arrays.asList(
"https://vc.zzeung.kr/credentials/mobile_authentication/kor/v1.json"))
.credentialType("MobileAuthenticationKorCredential")
.property(requireProperty)
.build();
JsonLdVpr vpr = null;
try {
vpr = new JsonLdVpr.Builder()
.context(Arrays.asList("https://vc.zzeung.kr/credentials/v1.json"))
.id("https://www.ubplus.com/vpr/mobile") // VPR ID로 아무 값이나 입력.
.purpose("휴대폰 인증서로 본인 확인") // VC 요청의 목적을 입력.
.verifier(mDidKeyHolder.getDid())
.condition(condition)
.build();
} catch (Exception e) {
e.printStackTrace();
}
ClaimRequest reqPresentation = new ClaimRequest.PresentationBuilder()
.didKeyHolder(mDidKeyHolder)
.requestDate(new Date())
.nonce(mNonce)
.publicKey(verifierPublicKey)
.version("2.0")
.vpr(vpr)
.build();
ProtocolMessage reqPresentationPm = null;
try {
reqPresentationPm = new ProtocolMessage.RequestBuilder()
.type(ProtocolType.REQUEST_PRESENTATION)
.claimRequest(reqPresentation)
.build();
} catch (Exception e) {
e.printStackTrace();
}
ProtocolMessage.SignResult reqPresentationSignResult =
reqPresentationPm.signEncrypt(mDidKeyHolder);
if (!reqPresentationSignResult.isSuccess()) {
System.out.println("Signing RequestPresentation failed.");
// mDidKeyHolder의 key store파일이 문제가 없는지 확인 필요.
return null;
}
JsonObject reqPresentationObject = reqPresentationSignResult.getResult();
System.out.println("VPR : " + reqPresentationObject.toString());
return reqPresentationObject.toString();
}
public boolean verifyPresentationForPhoneId(String PRESENTATION_JWE) {
ProtocolMessage presentationPm = ProtocolMessage.valueOf(PRESENTATION_JWE);
String keyId = presentationPm.getJweKid();
if (presentationPm.isProtected()) {
presentationPm.decryptJwe(mServerECDHKey);
}
System.out.println("decryptJWT :" + presentationPm.getJwtToken());
Presentation presentation = presentationPm.getPresentationJwt();
String holderDid = presentation.getDid();
String holderKeyId = presentation.getKeyId();
Document holderDoc = null;
try {
if (NODE_CONNECT_TYPE == NodeConnectType.MYID_WAS) {
// MyID WAS로 부터 Holder DID Document 조회.
holderDoc = mVerifierService.getDid(holderDid);
} else {
// Blockchain에서 Holder DID Document 조회
holderDoc = mDidService.readDocument(holderDid);
}
} catch (Exception e) {
e.printStackTrace();
}
if (holderDoc == null) {
System.out.println("Presentation holderDoc is null");
// blockchain에서 Holder의 DID 확인 실패
return false;
}
PublicKeyProperty publicKeyProperty =
holderDoc.getPublicKeyProperty(holderKeyId);
if (publicKeyProperty == null || publicKeyProperty.isRevoked()) {
System.out.println("Presentation holderDid revoked");
// Holder의 public key가 없거나 폐기되어서 서명 확인 불가.
return false;
}
PublicKey publicKey = publicKeyProperty.getPublicKey();
presentation.getJwt();
try {
Jwt.VerifyResult verifyResult = presentation.getJwt().verify(publicKey);
if (!verifyResult.isSuccess()) {
System.out.println(verifyResult.getFailMessage()); // verify fail
// Holder의 서명 확인 실패.
// 즉 이 presentation은 위조 되었거나 holder의 서명에 문제가 있음.
return false;
}
} catch (Exception e) {
e.printStackTrace();
}
// presentation내의 VC 검증 시작
for (VpCriteria criteria : presentation.getVp().getFulfilledCriteria()) {
Credential credential = Credential.valueOf(criteria.getVc());
// presentation을 제출한 주체가 VC의 발급받은 자와 동일한지만 확인
if (!credential.getTargetDid().equals(holderDid)) {
System.out.println("VC's targetDid does not match holderDid.");
return false;
}
Document issuerDocument = null;
String issuerDid = credential.getIssuerDid().getDid();
try {
if (NODE_CONNECT_TYPE == NodeConnectType.MYID_WAS) {
// MyID WAS로 부터 Holder DID Document 조회.
issuerDocument = mVerifierService.getDid(issuerDid);
} else {
// Blockchain에서 Holder DID Document 조회
issuerDocument = mDidService.readDocument(issuerDid);
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
if (issuerDocument == null) {
// blockchain에서 Holder의 DID 확인 실패
return false;
}
PublicKeyProperty issuerKeyProperty =
issuerDocument.getPublicKeyProperty(credential.getKeyId());
if (issuerKeyProperty.isRevoked()) {
// Issuer의 key가 폐기 되었음.
return false;
}
try {
PublicKey issuerPublicKey = issuerKeyProperty.getPublicKey();
Jwt.VerifyResult credVerifyResult = credential.getJwt().verify(issuerPublicKey);
if (!credVerifyResult.isSuccess()) {
// Issuer key로 VC 서명 검증 실패.
return false;
}
if (!holderDid.equals(credential.getTargetDid())) {
// VC에 있는 Holder DID와 presentation을 제출한 Holder의 DID가 다름.
return false;
}
} catch (AlgorithmException e) {
e.printStackTrace();
return false;
}
// 크레덴셜의 신원정보 무결성 체크: VC 내의 claim hash 값과 전달받은 실제 값을 hash하여 비교
if (!criteria.isVerifyParam()) {
System.out.println("Claim parameter hash is invalid.");
// credential 신원정보 무결성 체크 실패!
// credential 내의 claim hash 값과 param으로 전달받은 실제 값의 hash를 비교 실패.
// 즉 credential의 신원정보가 위변조 되었을 수 있음.
return false;
}
// 휴대폰 본인인증의 claim 정보.
Map<String, Claim> claimMap = criteria.getVcParam().getClaim();
// 요청한 항목이 presentation에 포함 되어 있는지 확인
if (!claimMap.containsKey("name")) {
// name : "홍길동"
System.out.println("Claim parameter does not have `name`");
}
if (!claimMap.containsKey("birthDate")) {
// birthDate (xsd:date): "1994-05-22"
System.out.println("Claim parameter does not have `birthDate`");
}
}
return true;
}
public boolean registerCredentialViaMyIDServer(ProtocolMessage credentialPm) {
Credential credential = credentialPm.getCredentialJwt();
BaseService.ServiceResult result = null;
try {
result = mIssuerService.registerVC(credential, mDidKeyHolder);
} catch (AlgorithmException e) {
e.printStackTrace();
return false;
}
if (!result.isSuccess()) {
// register fail
return false;
}
return true;
}
public boolean registerCredentialViaScore(ProtocolMessage credentialPm) {
Credential credential = credentialPm.getCredentialJwt();
Date issueDate = new Date();
Date expiryDate = credential.getJwt().getPayload().getExp();
CredentialInfo credentialInfo = new CredentialInfo.Builder()
.type(foundation.icon.myid.core.PropertyName.CREDENTIAL_INFO_TYPE_REGIST)
.issuerDid(credential.getDid())
.sig(credentialPm.getJwt().getSignature())
.issueDate(issueDate)
.expiryDate(expiryDate)
.build();
Jwt addJwt = CredentialInfoScoreParameter.CredentialInfoParam(
mDidKeyHolder, credentialInfo);
String signedJwt = null;
try {
signedJwt = mDidKeyHolder.sign(addJwt);
TransactionResult result = mVcService.register(mWallet, signedJwt);
if (result.getStatus().intValue() == 0) {
System.out.println("Registering VcScore failed.");
// blockchain에 VC 등록 실패.
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
public void getCredentialInfoViaScore() {
String signedJwt = "eyJ.."; // Credential JWT token
Credential credential = Credential.valueOf(signedJwt);
String issuerDid = credential.getDid();
String sig = Jwt.decode(signedJwt).getSignature();
CredentialInfo credentialInfo = null;
try {
credentialInfo = mVcService.get(sig);
} catch (IOException e) {
e.printStackTrace();
}
// vc를 검증.
if (credentialInfo.getIsRevoke()) {
System.out.println("vc is revoked.");
}
Date expiryDate = new Date(credentialInfo.getExpiryDate() * 1000L);
if (expiryDate.before(new Date())) {
System.out.println("vc is expired");
}
}
public void getCredentialInfoViaMyIDServer() {
String signedJwt = "eyJ.."; // Credential JWT token
Credential credential = Credential.valueOf(signedJwt);
String issuerDid = credential.getDid();
String sig = Jwt.decode(signedJwt).getSignature();
CredentialInfo credentialInfo = mIssuerService.getVC(issuerDid, sig);
if (credentialInfo == null) {
System.out.println("vc is null.");
}
// vc를 검증.
if (credentialInfo.getIsRevoke()) {
System.out.println("vc is revoked.");
}
Date expiryDate = new Date(credentialInfo.getExpiryDate() * 1000L);
if (expiryDate.before(new Date())) {
System.out.println("vc is expired");
}
}
public void revokeCredentialInfoViaScore(String vcSignature) {
RevokeCredentialInfo revokedCrendentialInfo = new RevokeCredentialInfo.Builder()
.type("REVOKE")
.issuerDid(mDidKeyHolder.getDid()) // issuerDid
.sig(vcSignature) // 폐기할 VC의 signature
.revokeDate(new Date()) // 폐기하는 현재시간
.build();
try {
Jwt revokeJwt = RevokeCredentialInfoScoreParameter
.RevokeCredentialInfoParam(mDidKeyHolder, revokedCrendentialInfo);
String signedRevokeJwt = mDidKeyHolder.sign(revokeJwt);
TransactionResult result =
mVcService.revoke(mWallet, signedRevokeJwt);
} catch (TransactionException e) {
String errorCodeString = e.getCode();
if ("158".equals(errorCodeString)) {
// 이미 폐기된 VC_ID
} else if ("144".equals(errorCodeString)) {
// 폐기할 VC_ID가 blockchain에 없음.
} else if ("136".equals(errorCodeString)) {
// 이슈어 private key로 jwt 서명 실패. key store 파일이 문제 없는지 확인 필요.
} else {
// 그 외 에러.
}
} catch (IOException e) {
// Failed to revoke public key
// 네트워크 에러
return;
} catch (AlgorithmException e) {
// Failed to sign
// key store 파일이 문제가 없는지 확인 필요.
return;
}
}
public void revokeCredentialInfoViaMyIDServer(String vcSignature) {
BaseService.ServiceResult result = null;
try {
result = mIssuerService.revokeVC(vcSignature, mDidKeyHolder.getDid(), mDidKeyHolder);
} catch (AlgorithmException e) {
// Failed to revoke VC
e.printStackTrace();
}
if (!result.isSuccess()) {
// Failed to revoke VC
}
}
/**
* Verify Revocation Request and returns siganture to revoke.
*
* @param requestRevocationJwt
* @return
*/
public String receiveRequestRevocation(String requestRevocationJwt) {
ProtocolMessage protocolMessage = ProtocolMessage.valueOf(requestRevocationJwt);
ClaimRequest claimRequest = protocolMessage.getClaimRequestJwt();
// holder DID Document를 조회.
String holderDid = claimRequest.getDid();
String holderKeyId = claimRequest.getKeyId();
Document holderDoc = null;
try {
if (NODE_CONNECT_TYPE == NodeConnectType.MYID_WAS) {
// MyID WAS로 부터 Holder DID Document 조회.
holderDoc = mVerifierService.getDid(holderDid);
} else {
// Blockchain에서 Holder DID Document 조회
holderDoc = mDidService.readDocument(holderDid);
}
} catch (Exception e) {
e.printStackTrace();
}
if (holderDoc == null) {
System.out.println("Presentation holderDoc is null");
// blockchain에서 Holder의 DID 확인 실패
return null;
}
PublicKeyProperty publicKeyProperty =
holderDoc.getPublicKeyProperty(holderKeyId);
if (publicKeyProperty == null || publicKeyProperty.isRevoked()) {
System.out.println("Presentation holderDid revoked");
// Holder의 public key가 없거나 폐기되어서 서명 확인 불가.
return null;
}
PublicKey holderPublicKey = publicKeyProperty.getPublicKey();
try {
Jwt.VerifyResult verifyResult = claimRequest.getJwt().verify(holderPublicKey);
System.out.println("verifyResult:" + verifyResult);
if (!verifyResult.isSuccess()) {
System.out.println(verifyResult.getFailMessage());
return null;
}
} catch (AlgorithmException e) {
System.out.println("Failed to verify request_revocation jwt. msg:" + e.getMessage());
return null;
}
// sig 추출
String revocationSig = claimRequest.getSig();
System.out.println("Signature to revoke:" + revocationSig);
return revocationSig;
}
/**
* Return Revocation Result
* @param requestRevocationJwt
* @param success
* @return
*/
public String responseRevocation(String requestRevocationJwt, boolean success) {
ResponseResult responseResult = null;
if (success) {
responseResult = new ResponseResult.Builder()
.result(true)
.build();
} else {
responseResult = new ResponseResult.Builder()
.result(false)
.errorCode("100")
.errorMessage("Fail to verify signature.")
.build();
}
ProtocolMessage pm = ProtocolMessage.valueOf(requestRevocationJwt);
ClaimRequest claimRequest = pm.getClaimRequestJwt();
String holderDid = claimRequest.getDid();
ClaimResponse claimResponse = new ClaimResponse.Builder(ClaimResponse.Type.REVOCATION)
.didKeyHolder(mDidKeyHolder)
.responseId(holderDid) // issuer's did
.version("2.0")
.responseResult(responseResult)
.build();
ProtocolMessage protocolMessage = new ProtocolMessage.ResponseBuilder()
.type(ProtocolType.RESPONSE_REVOCATION)
.claimResponse(claimResponse)
.build();
ProtocolMessage.SignResult signResult = protocolMessage.signEncrypt(mDidKeyHolder);
if (!signResult.isSuccess()) {
System.out.println("Signing RequestRevocation failed.");
return null;
}
System.out.println("JWT(RESPONE_REVOCATION) : " + signResult.getResult().toString());
System.out.println();
return signResult.getResult().toString();
}
}