Skip to content

Commit

Permalink
feat: Added support for OIDC4VP Test for HEDERA #1797
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed Aug 16, 2023
1 parent 8fc19b3 commit 73d4c68
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 59 deletions.
8 changes: 4 additions & 4 deletions lib/app/shared/enum/type/oidc4vc_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ enum OIDC4VCType {
],
subjectSyntaxTypesSupported: ['did:key'],
schemaForType: false,
publicJWKNeeded: true,
publicJWKNeeded: false,
serviceDocumentation:
'''WORK IN PROGRESS. WE use JSON-LD VC and VP and last release of the specs.\n'''
'''oidc4vci_draft : https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html\n'''
Expand Down Expand Up @@ -107,7 +107,7 @@ enum OIDC4VCType {
],
subjectSyntaxTypesSupported: ['did:key', 'did:pkh'],
schemaForType: false,
publicJWKNeeded: true,
publicJWKNeeded: false,
serviceDocumentation:
'''WORK IN PROGRESS EON project. last release of the specs.\n'''
'''oidc4vci_draft : https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html\n'''
Expand Down Expand Up @@ -136,7 +136,7 @@ enum OIDC4VCType {
],
subjectSyntaxTypesSupported: ['did:key'],
schemaForType: false,
publicJWKNeeded: true,
publicJWKNeeded: false,
serviceDocumentation: 'New environment for V3 compliance test',
),

Expand All @@ -157,7 +157,7 @@ enum OIDC4VCType {
],
subjectSyntaxTypesSupported: ['did:ion', 'did:web'],
schemaForType: false,
publicJWKNeeded: true,
publicJWKNeeded: false,
serviceDocumentation:
'https://identity.foundation/jwt-vc-presentation-profile/',
);
Expand Down
150 changes: 95 additions & 55 deletions lib/scan/cubit/scan_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,64 @@ class ScanCubit extends Cubit<ScanState> {

try {
if (uri.toString().startsWith('openid')) {
OIDC4VCType? currentOIIDC4VCType;

if (isFromPresentation) {
currentOIIDC4VCType = profileCubit.state.model.oidc4vcType;
} else {
for (final oidc4vcType in OIDC4VCType.values) {
if (oidc4vcType.isEnabled &&
uri.toString().startsWith(oidc4vcType.offerPrefix)) {
currentOIIDC4VCType = oidc4vcType;
}
}
}

if (currentOIIDC4VCType == null) {
throw Exception();
}

final OIDC4VC oidc4vc = currentOIIDC4VCType.getOIDC4VC;

final mnemonic =
await getSecureStorage.get(SecureStorageKeys.ssiMnemonic);
final privateKey = await oidc4vc.privateKeyFromMnemonic(
mnemonic: mnemonic!,
index: currentOIIDC4VCType.index,
);

late String did;
late String kid;

if (currentOIIDC4VCType == OIDC4VCType.EBSIV2) {
final private = await oidc4vc.getPrivateKey(mnemonic, privateKey);

final thumbprint = getThumbprint(private);
final encodedAddress = Base58Encode([2, ...thumbprint]);
did = 'did:ebsi:z$encodedAddress';
final lastPart = Base58Encode(thumbprint);
kid = '$did#$lastPart';
} else {
const didMethod = AltMeStrings.defaultDIDMethod;
did = didKitProvider.keyToDID(didMethod, privateKey);
kid = await didKitProvider.keyToVerificationMethod(
didMethod,
privateKey,
);
}

final responseType = uri.queryParameters['response_type'] ?? '';

if (uri.toString().startsWith('openid://')) {
await presentCredentialToOIDC4VPAndSiopV2Request(
credentialsToBePresented: credentialsToBePresented,
isFromPresentation: isFromPresentation,
issuer: issuer,
uri: uri,
oidc4vc: oidc4vc,
did: did,
kid: kid,
privateKey: privateKey,
);
return;
}
Expand All @@ -86,12 +137,18 @@ class ScanCubit extends Cubit<ScanState> {
final redirectUri = uri.queryParameters['redirect_uri'] ?? '';
final nonce = uri.queryParameters['nonce'] ?? '';
await presentCredentialToOID4VPRequest(
uri: uri,
issuer: issuer,
credentialsToBePresented: credentialsToBePresented,
nonce: nonce,
presentationDefinition:
credentialModel.credentialManifest!.presentationDefinition!,
redirectUri: redirectUri,
oidc4vcType: currentOIIDC4VCType,
oidc4vc: oidc4vc,
did: did,
kid: kid,
privateKey: privateKey,
);
return;
} else {
Expand Down Expand Up @@ -534,60 +591,18 @@ class ScanCubit extends Cubit<ScanState> {
required Issuer issuer,
required Uri uri,
required bool isFromPresentation,
required OIDC4VC oidc4vc,
required String privateKey,
required String did,
required String kid,
}) async {
final log =
getLogger('ScanCubit - presentCredentialToOIDC4VPAndSiopV2Request');
try {
OIDC4VCType? currentOIIDC4VCType;

if (isFromPresentation) {
currentOIIDC4VCType = profileCubit.state.model.oidc4vcType;
} else {
for (final oidc4vcType in OIDC4VCType.values) {
if (oidc4vcType.isEnabled &&
uri.toString().startsWith(oidc4vcType.offerPrefix)) {
currentOIIDC4VCType = oidc4vcType;
}
}
}

if (currentOIIDC4VCType == null) {
throw Exception();
}

final OIDC4VC oidc4vc = currentOIIDC4VCType.getOIDC4VC;
final mnemonic =
await getSecureStorage.get(SecureStorageKeys.ssiMnemonic);
final privateKey = await oidc4vc.privateKeyFromMnemonic(
mnemonic: mnemonic!,
index: currentOIIDC4VCType.index,
);

late String did;
late String kid;

if (currentOIIDC4VCType.issuerVcType == 'ldp_vc') {
const didMethod = AltMeStrings.defaultDIDMethod;
did = didKitProvider.keyToDID(didMethod, privateKey);
kid = await didKitProvider.keyToVerificationMethod(
didMethod,
privateKey,
);
} else if (currentOIIDC4VCType.issuerVcType == 'jwt_vc') {
final private = await oidc4vc.getPrivateKey(mnemonic, privateKey);

final thumbprint = getThumbprint(private);
final encodedAddress = Base58Encode([2, ...thumbprint]);
did = 'did:ebsi:z$encodedAddress';
final lastPart = Base58Encode(thumbprint);
kid = '$did#$lastPart';
} else {
throw Exception();
}

final credentialList =
credentialsToBePresented!.map((e) => jsonEncode(e.toJson())).toList();
final credentialList =
credentialsToBePresented!.map((e) => jsonEncode(e.toJson())).toList();

try {
await oidc4vc.sendPresentation(
uri,
credentialList,
Expand Down Expand Up @@ -639,15 +654,40 @@ class ScanCubit extends Cubit<ScanState> {
required String nonce,
required String redirectUri,
required Issuer issuer,
required OIDC4VC oidc4vc,
required OIDC4VCType oidc4vcType,
required String privateKey,
required String did,
required String kid,
required Uri uri,
}) async {
final log = getLogger('ScanCubit - presentCredentialToOID4VPRequest');
emit(state.loading());
await Future<void>.delayed(const Duration(milliseconds: 500));

try {
final vpToken = await createVpToken(
credentialsToBePresented: credentialsToBePresented!,
challenge: nonce,
);
late String vpToken;

if (oidc4vcType.issuerVcType == 'ldp_vc') {
vpToken = await createVpToken(
credentialsToBePresented: credentialsToBePresented!,
challenge: nonce,
);
} else if (oidc4vcType.issuerVcType == 'jwt_vc') {
final credentialList = credentialsToBePresented!
.map((e) => jsonEncode(e.toJson()))
.toList();

vpToken = await oidc4vc.extractVpToken(
uri: uri,
credentialsToBePresented: credentialList,
did: did,
kid: kid,
privateKey: privateKey,
);
} else {
throw Exception();
}

final uuid1 = const Uuid().v4();

Expand All @@ -661,7 +701,7 @@ class ScanCubit extends Cubit<ScanState> {
if (presentationDefinition.inputDescriptors.length == 1) {
inputDescriptors.add({
'id': presentationDefinition.inputDescriptors[0].id,
'format': 'ldp_vc', // type of the VC
'format': oidc4vcType.issuerVcType,
'path': r'$.verifiableCredential'
});
} else {
Expand All @@ -670,7 +710,7 @@ class ScanCubit extends Cubit<ScanState> {
i++) {
inputDescriptors.add({
'id': presentationDefinition.inputDescriptors[i].id,
'format': 'ldp_vc', // type of the VC
'format': oidc4vcType.issuerVcType,
// ignore: prefer_interpolation_to_compose_strings
'path': r'$.verifiableCredential[' + i.toString() + ']'
});
Expand Down
28 changes: 28 additions & 0 deletions packages/oidc4vc/lib/src/oidc4vc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,34 @@ class OIDC4VC {
}
}

Future<String> extractVpToken({
required Uri uri,
required List<String> credentialsToBePresented,
required String did,
required String kid,
String? mnemonic,
String? privateKey,
}) async {
try {
final private = await getPrivateKey(mnemonic, privateKey);

final tokenParameters = VerifierTokenParameters(
private,
did,
kid,
uri,
credentialsToBePresented,
uri.queryParameters['nonce'] ?? '',
);

final vpToken = await getVpToken(tokenParameters);

return vpToken;
} catch (e) {
throw Exception(e);
}
}

Future<void> proveOwnershipOfDid({
required Uri uri,
required String did,
Expand Down

0 comments on commit 73d4c68

Please sign in to comment.