Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Chralu committed Jun 5, 2024
1 parent 8374f05 commit 4f039c7
Show file tree
Hide file tree
Showing 20 changed files with 186 additions and 110 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package net.archethic.yubikit_android.methods

import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel

class Connect : MethodHandler {
override fun handle(call: MethodCall, result: MethodChannel.Result) {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.archethic.yubikit_android.methods

import androidx.annotation.NonNull
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel

interface MethodHandler {
fun handle(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result);
}
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3

COCOAPODS: 1.11.3
COCOAPODS: 1.12.0
4 changes: 3 additions & 1 deletion example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -205,6 +205,7 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand Down Expand Up @@ -241,6 +242,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand Down
2 changes: 1 addition & 1 deletion example/lib/components/capabilities_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class CapabilitiesText extends StatelessWidget {

Future<String> capabilitiesString() async {
try {
final capabilities = await yubikitPlugin.general.deviceCapabilities;
final capabilities = await yubikitPlugin.connection.deviceCapabilities;
return 'nfc : ${capabilities.nfc}, wired : ${capabilities.wired}';
} on PlatformException {
return 'Failed to get device capabilities';
Expand Down
14 changes: 11 additions & 3 deletions example/lib/components/generate_key_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ class GenerateKeyButton extends StatelessWidget {
Widget build(BuildContext context) => ActionButton(
text: 'Generate key',
onPressed: () async {
final publicKey = await yubikitPlugin.piv.generateKey(
pin: "123456",
managementKey: PivManagementKey.fromString(
final connection = await yubikitPlugin.connection.connect(
timeout: const Duration(seconds: 15),
);
final piv = await connection.pivSession;

await piv.verifyPin("123456");
await piv.authenticate(
PivManagementKey.fromString(
"010203040506070801020304050607080102030405060708",
keyType: PivManagementKeyType.tripleDES,
),
);

final publicKey = await piv.generateKey(
pinPolicy: PivPinPolicy.defaultPolicy,
type: PivKeyType.eccp256,
touchPolicy: PivTouchPolicy.defaultPolicy,
Expand Down
8 changes: 6 additions & 2 deletions example/lib/components/piv_calculate_secret_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ class PivCalculateSecretButton extends StatelessWidget {
Widget build(BuildContext context) => ActionButton(
text: 'Calculate secret',
onPressed: () async {
final secret = await yubikitPlugin.piv.calculateSecret(
final connection = await yubikitPlugin.connection.connect();
final piv = await connection.pivSession;

piv.verifyPin("123456");

final secret = await piv.calculateSecret(
slot: PivSlot.authentication,
pin: "123456",
peerPublicKey: """
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElqeFrBCjtonol5ksKYCuXf+alUTI
Expand Down
8 changes: 5 additions & 3 deletions example/lib/components/piv_read_cert_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ class PivReadCertButton extends StatelessWidget {
Widget build(BuildContext context) => ActionButton(
text: 'Read certificate',
onPressed: () async {
final certificate = await yubikitPlugin.piv.getCertificate(
pin: "123456",
final connection = await yubikitPlugin.connection.connect();
final piv = await connection.pivSession;
await piv.verifyPin("123456");
final publicKey = await piv.getCertificate(
slot: PivSlot.signature,
);
return String.fromCharCodes(certificate);
return String.fromCharCodes(publicKey);
},
);
}
1 change: 0 additions & 1 deletion ios/Classes/handlers/PivCalculateSecret.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ class PivCalculateSecretHandler: Handler {

return
}

pivSession.verifyPin(pin) { retries, verifyPinError in
guard verifyPinError == nil else {
context.failure(
Expand Down
18 changes: 18 additions & 0 deletions lib/src/domain/protocol/connection/protocol.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:yubidart/yubidart.dart';

abstract class Connection {
Future<PivProtocol> get pivSession;

Future<OTPProtocol> get otpSession;
}

abstract class ConnectionProtocol {
/// Looks at the device capabilities (connectivity mainly)
Future<DeviceCapabilities> get deviceCapabilities;

Future<Connection> connect({
Duration timeout = const Duration(minutes: 1),
});

Future<void> disconnect();
}
6 changes: 0 additions & 6 deletions lib/src/domain/protocol/general/protocol.dart

This file was deleted.

18 changes: 10 additions & 8 deletions lib/src/domain/protocol/piv/protocol.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import 'package:yubidart/src/domain/model/piv/slot.dart';
import 'package:yubidart/src/domain/model/piv/touch_policy.dart';

abstract class PivProtocol {
/// Verifies the PIN code.
///
/// [pin] The pin. Default pin code is 123456.
Future<PivProtocol> verifyPin(String pin);

/// Authenticates with the management key
///
/// [managementKey] The management key. Default value is 000102030405060708090A0B0C0D0E0F1011121314151617.
Future<PivProtocol> authenticate(PivManagementKey managementKey);

/// Generates a new key pair within the YubiKey.
/// This method requires authentication and pin verification.
///
Expand All @@ -16,8 +26,6 @@ abstract class PivProtocol {
/// TouchPolicy.CACHED requires support for touch cached, available on YubiKey 4.3 or later.
/// This method is thread safe and can be invoked from any thread (main or a background thread).
///
/// [pin] The pin. Default pin code is 123456.
/// [managementKey] The management key. Default is 010203040506070801020304050607080102030405060708.
/// [slot] The slot to generate the new key in.
/// [type] Which algorithm is used for key generation.
/// [pinPolicy] The PIN policy for using the private key.
Expand All @@ -27,8 +35,6 @@ abstract class PivProtocol {
///
/// Throws a YKFailure
Future<Uint8List> generateKey({
required String pin,
required PivManagementKey managementKey,
required PivSlot slot,
required PivKeyType type,
required PivPinPolicy pinPolicy,
Expand All @@ -37,28 +43,24 @@ abstract class PivProtocol {

/// Reads the X.509 certificate stored in the specified slot on the YubiKey.
///
/// [pin] The pin. Default pin code is 123456.
/// [slot] : The slot where the certificate is stored.
///
/// Returns certificate instance
///
/// Throws a YKFailure
Future<Uint8List> getCertificate({
required String pin,
required PivSlot slot,
});

/// Perform an ECDH operation with a given public key to compute a shared secret.
///
/// [pin] The pin. Default pin code is 123456.
/// [slot] The slot containing the private EC key to use.
/// [peerPublicKey] The peer public key for the operation. This is an EllipticCurve encryption public key in PEM format.
///
/// Returns the shared secret, comprising the x-coordinate of the ECDH result point.
///
/// Throws a YKFailure
Future<Uint8List> calculateSecret({
required String pin,
required PivSlot slot,
required String peerPublicKey,
});
Expand Down
2 changes: 1 addition & 1 deletion lib/src/domain/protocol/protocol.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export 'general/protocol.dart';
export 'connection/protocol.dart';
export 'otp/otp.dart';
export 'piv/protocol.dart';
12 changes: 3 additions & 9 deletions lib/src/domain/yubidart_platform_interface.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:yubidart/src/domain/protocol/general/protocol.dart';
import 'package:yubidart/src/domain/protocol/piv/protocol.dart';
import 'package:yubidart/src/domain/protocol/connection/protocol.dart';

abstract class YubidartPlatform extends PlatformInterface {
/// Constructs a [YubidartPlatform].
Expand All @@ -15,9 +14,7 @@ abstract class YubidartPlatform extends PlatformInterface {
/// Defaults to MethodChannelYubidart.
static YubidartPlatform get instance => _instance;

PivProtocol get piv;

GeneralProtocol get general;
ConnectionProtocol get connection;

/// Platform-specific implementations should set this with their own
/// platform-specific class that extends [YubidartPlatform] when
Expand All @@ -30,8 +27,5 @@ abstract class YubidartPlatform extends PlatformInterface {

class EmptyYubidartPlatformImplementation implements YubidartPlatform {
@override
GeneralProtocol get general => throw UnimplementedError();

@override
PivProtocol get piv => throw UnimplementedError();
ConnectionProtocol get connection => throw UnimplementedError();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'package:flutter/services.dart';
import 'package:yubidart/src/domain/model/failure/failure.dart';
import 'package:yubidart/src/domain/model/general/device_capabilities.dart';
import 'package:yubidart/src/domain/protocol/connection/protocol.dart';
import 'package:yubidart/src/domain/protocol/otp/otp.dart';
import 'package:yubidart/src/domain/protocol/piv/protocol.dart';
import 'package:yubidart/src/infrastructure/protocol/otp/default_otp_protocol.dart';
import 'package:yubidart/src/infrastructure/protocol/otp/yubicloud_client.dart';
import 'package:yubidart/src/infrastructure/protocol/piv/default_piv_protocol.dart';

class DefaultConnection implements Connection {
@override
Future<PivProtocol> get pivSession async => DefaultPivProtocol();

@override
Future<OTPProtocol> get otpSession async =>
DefaultOTPProtocol(yubicloudClient: YubicloudClient());
}

class DefaultConnectionProtocol implements ConnectionProtocol {
/// The method channel used to interact with the native platform.
// @foundation.visibleForTesting
final methodChannel = const MethodChannel('net.archethic/yubidart');

@override
Future<DeviceCapabilities> get deviceCapabilities => YKFailure.guard(
() async {
final supportsNFCScanning =
await methodChannel.invokeMethod<bool>('supportsNFCScanning');
final supportsISO7816NFCTags =
await methodChannel.invokeMethod<bool>('supportsISO7816NFCTags');
final supportsMFIAccessoryKey =
await methodChannel.invokeMethod<bool>('supportsMFIAccessoryKey');

if (supportsNFCScanning == null ||
supportsISO7816NFCTags == null ||
supportsMFIAccessoryKey == null) {
throw YKFailure.other();
}

return DeviceCapabilities(
nfc: supportsNFCScanning || supportsISO7816NFCTags,
wired: supportsMFIAccessoryKey,
);
},
);

@override
Future<Connection> connect({
Duration timeout = const Duration(minutes: 1),
}) {
return YKFailure.guard(
() async {
await methodChannel.invokeMethod(
'connect',
);
return DefaultConnection();
},
);
}

@override
Future<void> disconnect() {
return YKFailure.guard(
() async {
await methodChannel.invokeMethod(
'disconnect',
);
},
);
}
}

This file was deleted.

Loading

0 comments on commit 4f039c7

Please sign in to comment.