Skip to content

Commit

Permalink
feat: Attempt to add clientIdScheme feature
Browse files Browse the repository at this point in the history
  • Loading branch information
bibash28 committed Apr 2, 2024
1 parent 83080f2 commit 09740a1
Showing 1 changed file with 112 additions and 10 deletions.
122 changes: 112 additions & 10 deletions lib/dashboard/qr_code/qr_code_scan/cubit/qr_code_scan_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ import 'package:altme/polygon_id/polygon_id.dart';
import 'package:altme/query_by_example/query_by_example.dart';
import 'package:altme/scan/scan.dart';
import 'package:altme/wallet/cubit/wallet_cubit.dart';
import 'package:asn1lib/asn1lib.dart' as asn1lib;
import 'package:beacon_flutter/beacon_flutter.dart';
import 'package:bloc/bloc.dart';
import 'package:credential_manifest/credential_manifest.dart';
import 'package:dart_jsonwebtoken/dart_jsonwebtoken.dart';
import 'package:did_kit/did_kit.dart';
import 'package:dio/dio.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:jwt_decode/jwt_decode.dart';
import 'package:oidc4vc/oidc4vc.dart';
import 'package:pointycastle/pointycastle.dart' as pc;
import 'package:secure_storage/secure_storage.dart';

import 'package:x509/x509.dart' as x509;
part 'qr_code_scan_cubit.g.dart';
part 'qr_code_scan_state.dart';

Expand Down Expand Up @@ -1059,32 +1062,55 @@ class QRCodeScanCubit extends Cubit<QRCodeScanState> {
.selfSovereignIdentityOptions.customOidc4vcProfile;

final isSecurityEnabled = customOidc4vcProfile.securityLevel;
final enableJWKThumbprint =
customOidc4vcProfile.clientType == ClientType.jwkThumbprint;

if (isSecurityEnabled && enableJWKThumbprint) {
if (isSecurityEnabled) {
final Map<String, dynamic> payload =
decodePayload(jwtDecode: jwtDecode, token: encodedData as String);

final String issuer = payload['client_id'].toString();
final String clientId = payload['client_id'].toString();

//check Signature
try {
/// client_id_scheme = did, you need tio use the universal resolver
///
/// client_id_scheme = redirect_uri
/// (default case if no client_id_scheme)c you need to use the jwks
///
/// client_id_scheme = x509_san_dns, you need the key from the
/// certificate
///
/// client_id_scheme = verifier_attestation, the key will be in a
/// jwt inside teh header
///
/// if client_id starts with "did:" lets consider it is
/// client_id_scheme n= did, universal resolver
///
/// if client_id starts with http, lets consider it is
/// client_id_scheme = redirect_uri, fetch jwks
final clientIdScheme = payload['client_id_scheme'];

if (clientIdScheme != null) {
if (clientIdScheme == 'x509_san_dns') {
await checkX509(clientId: clientId, encodedData: encodedData);
}
}

final VerificationType isVerified = await verifyEncodedData(
issuer: issuer,
issuer: clientId,
jwtDecode: jwtDecode,
jwt: encodedData,
);

if (isVerified == VerificationType.verified) {
emit(state.acceptHost());
} else {
emitError(
if (isVerified != VerificationType.verified) {
return emitError(
ResponseMessage(
message: ResponseString.RESPONSE_STRING_invalidRequest,
),
);
}

emit(state.acceptHost());
} catch (e) {
emitError(
ResponseMessage(
Expand All @@ -1097,6 +1123,82 @@ class QRCodeScanCubit extends Cubit<QRCodeScanState> {
}
}

Future<void> checkX509({
required String encodedData,
required String clientId,
}) async {
final Map<String, dynamic> header =
decodeHeader(jwtDecode: jwtDecode, token: encodedData);

final x5c = header['x5c'];

if (x5c != null) {
if (x5c is! List) {
throw ResponseMessage(
data: {
'error': 'invalid_format',
'error_description': 'x509_san_dns scheme error',
},
);
}

//array x5c[0], it is a certificat in DER format (binary)
final certificate = x5c.firstOrNull;

if (certificate == null) {
throw ResponseMessage(
data: {
'error': 'invalid_format',
'error_description': 'x509_san_dns scheme error',
},
);
}

final decoded = base64Decode(certificate.toString());
final seq = asn1lib.ASN1Sequence.fromBytes(decoded);
final cert = x509.X509Certificate.fromAsn1(seq);

final subject = cert.tbsCertificate.subject;

// final publicKey = cert.publicKey as x509.PublicKey;
// if (publicKey is x509.RsaPublicKey) {
// print(publicKey.modulus.toString());
// print(publicKey.exponent);
// }

if (subject == null) {
throw ResponseMessage(
data: {
'error': 'invalid_format',
'error_description': 'x509_san_dns scheme error',
},
);
}

final names = subject.names;

if (names.isEmpty) {
throw ResponseMessage(
data: {
'error': 'invalid_format',
'error_description': 'x509_san_dns scheme error',
},
);
}

final value = names[0].entries.map((element) => element.value).toList();

if (!value.contains(clientId)) {
throw ResponseMessage(
data: {
'error': 'invalid_format',
'error_description': 'x509_san_dns scheme error',
},
);
}
}
}

/// complete SIOPV2 Flow
Future<void> completeSiopV2Flow() async {
try {
Expand Down

0 comments on commit 09740a1

Please sign in to comment.