Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce at_signing_algo and hashing_algo in at_auth_request and at_onboarding_request #608

Open
wants to merge 11 commits into
base: trunk
Choose a base branch
from
Open
34 changes: 19 additions & 15 deletions packages/at_auth/lib/src/at_auth_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,12 @@ class AtAuthImpl implements AtAuth {
'Unable to read PkamPrivateKey from provided atKeys file/atAuthKeys object',
exceptionScenario: ExceptionScenario.invalidValueProvided);
}
atLookUp ??= AtLookupImpl(
atAuthRequest.atSign, atAuthRequest.rootDomain, atAuthRequest.rootPort);
// ??= to support mocking
atChops ??= _createAtChops(atAuthKeys);
atLookUp ??= AtLookupImpl(
atAuthRequest.atSign, atAuthRequest.rootDomain, atAuthRequest.rootPort);
atLookUp!.signingAlgoType = atAuthRequest.signingAlgoType;
atLookUp!.hashingAlgoType = atAuthRequest.hashingAlgoType;
atLookUp!.atChops = atChops;

_logger.finer('Authenticating using PKAM');
Expand Down Expand Up @@ -103,10 +105,17 @@ class AtAuthImpl implements AtAuth {
@override
Future<AtOnboardingResponse> onboard(
AtOnboardingRequest atOnboardingRequest, String cramSecret) async {
if (atOnboardingRequest.authMode == PkamAuthMode.sim && atChops == null) {
throw AtPublicKeyNotFoundException(
'AtChops cannot be null when AuthMode is sim. '
'PKAMPublicKey needs to be read from sim using AtChops');
}
var atOnboardingResponse = AtOnboardingResponse(atOnboardingRequest.atSign);
atEnrollmentBase = AtEnrollmentImpl(atOnboardingRequest.atSign);
atLookUp ??= AtLookupImpl(atOnboardingRequest.atSign,
atOnboardingRequest.rootDomain, atOnboardingRequest.rootPort);
atLookUp?.signingAlgoType = atOnboardingRequest.signingAlgoType;
atLookUp?.hashingAlgoType = atOnboardingRequest.hashingAlgoType;

//1. cram auth
cramAuthenticator ??=
Expand All @@ -132,20 +141,15 @@ class AtAuthImpl implements AtAuth {
atOnboardingRequest, atAuthKeys, atLookUp!);
atAuthKeys.enrollmentId = enrollmentIdFromServer;

//4. Close connection to server
//4. Close existing authenticated connection to server
try {
await (atLookUp as AtLookupImpl).close();
} on Exception catch (e) {
_logger.severe('error while closing connection to server: $e');
}

//5. Init _atLookUp again and attempt pkam auth
// atLookUp = AtLookupImpl(atOnboardingRequest.atSign,
// atOnboardingRequest.rootDomain, atOnboardingRequest.rootPort);
atLookUp!.atChops = atChops;

var isPkamAuthenticated = false;
//6. Do pkam auth
//5. Do pkam auth
pkamAuthenticator ??=
PkamAuthenticator(atOnboardingRequest.atSign, atLookUp!);
try {
Expand All @@ -156,10 +160,10 @@ class AtAuthImpl implements AtAuth {
throw AtAuthenticationException('Pkam auth failed - $e ');
}
if (!isPkamAuthenticated) {
throw AtAuthenticationException('Pkam auth returned false');
throw AtAuthenticationException('Pkam auth unsuccessful');
}

//7. If Pkam auth is success, update encryption public key to secondary
//6. If Pkam auth is success, update encryption public key to secondary
// and delete cram key from server
final encryptionPublicKey = atAuthKeys.defaultEncryptionPublicKey;
UpdateVerbBuilder updateBuilder = UpdateVerbBuilder()
Expand All @@ -171,7 +175,7 @@ class AtAuthImpl implements AtAuth {
String? encryptKeyUpdateResult = await atLookUp!.executeVerb(updateBuilder);
_logger.info('Encryption public key update result $encryptKeyUpdateResult');

//8. Delete cram secret from the keystore as cram auth is complete
//7. Delete cram secret from the keystore as cram auth is complete
DeleteVerbBuilder deleteBuilder = DeleteVerbBuilder()
..atKey = (AtKey()..key = AtConstants.atCramSecret);
String? deleteResponse = await atLookUp!.executeVerb(deleteBuilder);
Expand Down Expand Up @@ -326,7 +330,7 @@ class AtAuthImpl implements AtAuth {
} else if (authMode == PkamAuthMode.sim) {
// get the public key from secure element
pkamPublicKey = atChops!.readPublicKey(publicKeyId!);
_logger.info('pkam public key from sim: ${atKeysFile.apkamPublicKey}');
_logger.info('PKAM public key from sim: $pkamPublicKey');

// encryption key pair and self encryption symmetric key
// are not available to injected at_chops. Set it here
Expand All @@ -335,8 +339,8 @@ class AtAuthImpl implements AtAuth {
atChops!.atChopsKeys.apkamSymmetricKey = apkamSymmetricKey;
}
atKeysFile.apkamPublicKey = pkamPublicKey;
//Standard order of an atKeys file is ->
// pkam keypair -> encryption keypair -> selfEncryption key -> enrollmentId --> apkam symmetric key -->
// Standard order of an atKeys file is -> pkam keypair -> encryption keypair
// --> selfEncryption key -> enrollmentId --> apkam symmetric key -->
// @sign: selfEncryptionKey[self encryption key again]
// note: "->" stands for "followed by"
atKeysFile.defaultEncryptionPublicKey =
Expand Down
3 changes: 1 addition & 2 deletions packages/at_auth/lib/src/auth/cram_authenticator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ class CramAuthenticator {
Future<AtAuthResponse> authenticate() async {
var authResult = AtAuthResponse(_atSign);
try {
bool cramResult =
authResult.isSuccessful =
await (atLookup as AtLookupImpl).cramAuthenticate(_cramSecret);
authResult.isSuccessful = cramResult;
} on UnAuthenticatedException catch (e) {
throw UnAuthenticatedException(
'cram auth failed for $_atSign - ${e.toString()}');
Expand Down
3 changes: 1 addition & 2 deletions packages/at_auth/lib/src/auth/pkam_authenticator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ class PkamAuthenticator {
Future<AtAuthResponse> authenticate({String? enrollmentId}) async {
var authResult = AtAuthResponse(_atSign);
try {
bool pkamResult =
authResult.isSuccessful =
await _atLookup.pkamAuthenticate(enrollmentId: enrollmentId);
authResult.isSuccessful = pkamResult;
} on UnAuthenticatedException catch (e) {
throw UnAuthenticatedException(
'pkam auth failed for $_atSign - ${e.toString()}');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ class AtOnboardingResponse {

@override
String toString() {
return 'AtOnboardingResponse{atSign: $atSign, enrollmentId: $enrollmentId, isSuccessful: $isSuccessful}';
return 'AtOnboardingResponse: {atSign: $atSign, enrollmentId: $enrollmentId, isSuccessful: $isSuccessful}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ class AtOnboardingServiceImpl implements AtOnboardingService {
atOnboardingRequest.deviceName = atOnboardingPreference.deviceName;
atOnboardingRequest.publicKeyId = atOnboardingPreference.publicKeyId;
atOnboardingRequest.authMode = atOnboardingPreference.authMode;
atOnboardingRequest.signingAlgoType =
atOnboardingPreference.signingAlgoType;
atOnboardingRequest.hashingAlgoType =
atOnboardingPreference.hashingAlgoType;

AtOnboardingResponse atOnboardingResponse = await atAuth!
.onboard(atOnboardingRequest, atOnboardingPreference.cramSecret!);
Expand Down Expand Up @@ -481,7 +485,9 @@ class AtOnboardingServiceImpl implements AtOnboardingService {
..authMode = atOnboardingPreference.authMode
..rootDomain = atOnboardingPreference.rootDomain
..rootPort = atOnboardingPreference.rootPort
..publicKeyId = atOnboardingPreference.publicKeyId;
..publicKeyId = atOnboardingPreference.publicKeyId
..signingAlgoType = atOnboardingPreference.signingAlgoType
..hashingAlgoType = atOnboardingPreference.hashingAlgoType;
var atAuthResponse = await atAuth!.authenticate(atAuthRequest);
logger.finer('Auth response: $atAuthResponse');
if (atAuthResponse.isSuccessful &&
Expand Down Expand Up @@ -654,7 +660,8 @@ class AtOnboardingServiceImpl implements AtOnboardingService {
@override
Future<void> close() async {
logger.info('Closing');
if (_atLookUp != null && (_atLookUp as AtLookupImpl).isConnectionAvailable()) {
if (_atLookUp != null &&
(_atLookUp as AtLookupImpl).isConnectionAvailable()) {
await _atLookUp!.close();
}
atClient?.notificationService.stopAllSubscriptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import 'package:at_onboarding_cli/src/activate_cli/activate_cli.dart'
as activate_cli;
import 'package:at_utils/at_utils.dart';
import 'package:test/test.dart';
import 'package:at_auth/src/at_auth_impl.dart';
import 'package:at_chops/at_chops.dart';

import 'utils/onboarding_service_impl_override.dart';

Expand Down Expand Up @@ -77,7 +79,7 @@ void main() {
AtOnboardingService onboardingService =
AtOnboardingServiceImpl(atSign, preference);
await onboardingService.authenticate();
AtClient? atClient = await onboardingService.atClient;
AtClient? atClient = onboardingService.atClient;
AtKey key = AtKey();
key.key = 'testKey3';
key.namespace = 'wavi';
Expand All @@ -86,6 +88,29 @@ void main() {
expect('value3', response?.value);
});

test(
'validate that signing algo and hashing algo set in AtOnboardingPreference is passed forward to AtAuth instance',
() async {
String atSign = '@eve🛠';
await _createKeys(atSign);
AtOnboardingPreference preference = getPreferences(atSign);
await generateAtKeysFile(atSign, preference.atKeysFilePath!);
SigningAlgoType signingAlgo = SigningAlgoType.rsa2048;
HashingAlgoType hashingAlgo = HashingAlgoType.sha512;
preference.hashingAlgoType = hashingAlgo;
preference.signingAlgoType = signingAlgo;
AtOnboardingService onboardingService =
AtOnboardingServiceImpl(atSign, preference);
await onboardingService.authenticate();
// validating on the atLookup instance in AtAuth to ensure that the algo's
// passed through OnboardingPref are passed to the AtLookup instance that
// communicates with the at_server
AtLookupImpl? atLookupImpl =
(onboardingService.atAuth as AtAuthImpl).atLookUp as AtLookupImpl?;
expect(atLookupImpl!.signingAlgoType, signingAlgo);
expect(atLookupImpl.hashingAlgoType, hashingAlgo);
});

test('A test to verify atKeysFilePath is set when null is provided',
() async {
String atSign = '@eve🛠';
Expand Down Expand Up @@ -115,7 +140,7 @@ void main() {
await generateAtKeysFile(atSign, atOnboardingPreference.atKeysFilePath!);
await _createKeys(atSign);
bool status = await atOnboardingService.authenticate();
atClient = await atOnboardingService.atClient;
atClient = atOnboardingService.atClient;
expect(true, status);

expect(at_demos.pkamPrivateKeyMap[atSign],
Expand Down Expand Up @@ -146,6 +171,7 @@ void main() {
() async {
AtOnboardingService atOnboardingService =
AtOnboardingServiceImpl(atSign, atOnboardingPreference);

bool status = await atOnboardingService.onboard();
expect(status, true);
bool status2 = await atOnboardingService.authenticate();
Expand All @@ -165,9 +191,6 @@ void main() {
// Skipping this test until the issue can be resolved
group('A group of tests to verify activate_cli', () {
String atSign = '@murali🛠';
AtOnboardingPreference onboardingPreference = getPreferences(atSign);
AtOnboardingService onboardingService =
OnboardingServiceImplOverride(atSign, onboardingPreference);
test(
'A test to verify atSign is activated and .atKeys file is generated using activate_cli',
() async {
Expand All @@ -182,10 +205,9 @@ void main() {
// perform activation of atSign
await activate_cli.wrappedMain(args);

/// ToDo: test should NOT exit with status 0 after activation is complete
/// Exiting with status 0 is ideal behaviour, but for the sake of the test we need to be
/// able to run the following assertions.

AtOnboardingPreference onboardingPreference = getPreferences(atSign);
AtOnboardingService onboardingService =
AtOnboardingServiceImpl(atSign, onboardingPreference);
// Authenticate atSign with the .atKeys file generated via the activate_cli tool
expect(await File(onboardingPreference.atKeysFilePath!).exists(), true);
expect(await onboardingService.authenticate(), true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import 'dart:io';

import 'package:at_chops/at_chops.dart';
import 'package:at_client/at_client.dart';
import 'package:at_lookup/at_lookup.dart';
import 'package:at_onboarding_cli/at_onboarding_cli.dart';
import 'package:at_utils/at_logger.dart';
import 'package:test/test.dart';
Expand All @@ -16,23 +15,20 @@ import 'utils/onboarding_service_impl_override.dart';
void main() {
AtSignLogger.root_level = 'WARNING';
var logger = AtSignLogger('OnboardSecureElementTest');

final atSign = '@egcreditbureau🛠'.trim();
test('Test auth functionality using secure element mock', () async {

test('Validate auth functionality using secure element mock', () async {
AtOnboardingPreference preference = getPreferences(atSign);
AtOnboardingService onboardingService =
OnboardingServiceImplOverride(atSign, preference);
// create empty keys in AtChops. Encryption key pair will be set later on after generation
final atChopsImpl =
AtChopsSecureElementMock(AtChopsKeys.create(null, null));
AtLookUp atLookupInstance =
AtLookupImpl(atSign, preference.rootDomain, preference.rootPort);
atLookupInstance.signingAlgoType = preference.signingAlgoType;
atLookupInstance.hashingAlgoType = preference.hashingAlgoType;
at_auth.AtAuth atAuthInstance = at_auth.atAuthBase
.atAuth(atLookUp: atLookupInstance, atChops: atChopsImpl);
at_auth.AtAuth atAuthInstance =
at_auth.atAuthBase.atAuth(atChops: atChopsImpl);
onboardingService.atAuth = atAuthInstance;
atChopsImpl.init();

logger.info('Onboarding the atSign: $atSign');
bool isOnboarded = await onboardingService.onboard();
expect(isOnboarded, true);
Expand All @@ -44,7 +40,7 @@ void main() {
logger.info('Authentication completed successfully for atSign: $atSign');

// update a key
AtClient? atClient = await onboardingService.atClient;
AtClient? atClient = onboardingService.atClient;
await insertSelfEncKey(atClient, atSign,
selfEncryptionKey:
await getSelfEncryptionKey(preference.atKeysFilePath!));
Expand Down Expand Up @@ -79,7 +75,7 @@ AtOnboardingPreference getPreferences(String atSign) {
..commitLogPath = 'storage/commitLog'
..rootDomain = 'vip.ve.atsign.zone'
..fetchOfflineNotifications = true
..atKeysFilePath = 'test/storage/files/$atSign' + '_key.atKeys'
..atKeysFilePath = 'test/storage/files/${atSign}_key.atKeys'
..signingAlgoType = SigningAlgoType.ecc_secp256r1
..hashingAlgoType = HashingAlgoType.sha256
..authMode = PkamAuthMode.sim
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AtChopsSecureElementMock extends AtChopsImpl {
..result = base64Signature
..atSigningMetaData = atSigningMetadata
..atSigningResultType = AtSigningResultType.string;
print('at signing result: $atSigningResult');
print('[AtChopsSecureElementMock] AtSigningResult: $atSigningResult');
return atSigningResult;
}

Expand All @@ -46,7 +46,7 @@ class AtChopsSecureElementMock extends AtChopsImpl {

@override
String readPublicKey(String publicKeyId) {
print('public key in read public key: ${eccPublicKey.toString()}');
print('[AtChopsSecureElementMock] Reading public key from SIM: ${eccPublicKey.toString()}');
return eccPublicKey.toString();
}
}
Loading