Skip to content

Commit

Permalink
add management key support for PIV
Browse files Browse the repository at this point in the history
  • Loading branch information
dangfan committed May 8, 2024
1 parent 7e0f72a commit 6abe4fd
Show file tree
Hide file tree
Showing 11 changed files with 453 additions and 117 deletions.
27 changes: 27 additions & 0 deletions lib/controller/applets/piv.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import 'dart:async';

import 'package:canokey_console/controller/base_controller.dart';
import 'package:canokey_console/generated/l10n.dart';
import 'package:canokey_console/helper/theme/admin_theme.dart';
import 'package:canokey_console/helper/utils/prompts.dart';
import 'package:canokey_console/helper/utils/smartcard.dart';
import 'package:convert/convert.dart';
import 'package:dart_des/dart_des.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:logging/logging.dart';
Expand Down Expand Up @@ -57,6 +61,29 @@ class PivController extends Controller {
});
}

Future<bool> verifyManagementKey(String key) async {
final c = new Completer<bool>();
SmartCard.process(() async {
SmartCard.assertOK(await SmartCard.transceive('00A4040005A000000308'));
String resp = await SmartCard.transceive('0087039B047C028100');
SmartCard.assertOK(resp);
String challenge = resp.substring(8, resp.length - 4);
DES3 des3 = DES3(key: hex.decode(key));
String auth = hex.encode(des3.encrypt(hex.decode(challenge))).substring(0, 16);
resp = await SmartCard.transceive('0087039B0C7C0A8208$auth');
c.complete(SmartCard.isOK(resp));
});
return c.future;
}

setManagementKey(String key) async {
SmartCard.process(() async {
SmartCard.assertOK(await SmartCard.transceive('00FFFFFF1B039B18$key'));
Navigator.pop(Get.context!);
Prompts.showPrompt(S.of(Get.context!).successfullyChanged, ContentThemeColor.success);
});
}

String _padPin(String pin) {
String pinHex = pin.codeUnits.map((e) => e.toRadixString(16)).join();
if (pinHex.length < 16) {
Expand Down
28 changes: 24 additions & 4 deletions lib/generated/intl/messages_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ class MessageLookup extends MessageLookupByLibrary {
static String m6(applet) =>
"This operation will RESET all data of ${applet}!";

static String m7(name) =>
static String m7(length) => "Need exact ${length} characters";

static String m8(name) =>
"This action will delete the account ${name} from your CanoKey. Make sure you have other ways to log in.";

final messages = _notInlinedMessages(_notInlinedMessages);
Expand Down Expand Up @@ -131,7 +133,7 @@ class MessageLookup extends MessageLookupByLibrary {
"oathTooLong": MessageLookupByLibrary.simpleMessage("Too long"),
"oathType": MessageLookupByLibrary.simpleMessage("Type"),
"off": MessageLookupByLibrary.simpleMessage("Off"),
"oldPin": MessageLookupByLibrary.simpleMessage("Old PIN"),
"oldPin": MessageLookupByLibrary.simpleMessage("Current PIN"),
"on": MessageLookupByLibrary.simpleMessage("On"),
"openpgpAuthentication":
MessageLookupByLibrary.simpleMessage("Authentication"),
Expand Down Expand Up @@ -188,12 +190,27 @@ class MessageLookup extends MessageLookupByLibrary {
"pinLength": MessageLookupByLibrary.simpleMessage(
"The provided PIN is too short or too long."),
"pinRetries": m4,
"pivChangeManagementKey":
MessageLookupByLibrary.simpleMessage("Change Management Key"),
"pivChangeManagementKeyPrompt": MessageLookupByLibrary.simpleMessage(
"New Management Key should be 24 bytes long. Please save it in a safe place."),
"pivChangePUK": MessageLookupByLibrary.simpleMessage("Change PUK"),
"pivChangePUKPrompt": m5,
"pivManagementKeyVerificationFailed":
MessageLookupByLibrary.simpleMessage(
"Management Key verification failed"),
"pivNewManagementKey":
MessageLookupByLibrary.simpleMessage("New Management Key"),
"pivNewPUK": MessageLookupByLibrary.simpleMessage("New PUK"),
"pivOldPUK": MessageLookupByLibrary.simpleMessage("Old PUK"),
"pivOldManagementKey":
MessageLookupByLibrary.simpleMessage("Current Management Key"),
"pivOldPUK": MessageLookupByLibrary.simpleMessage("Current PUK"),
"pivPinManagement":
MessageLookupByLibrary.simpleMessage("PIN Management"),
"pivRandomManagementKey":
MessageLookupByLibrary.simpleMessage("Random"),
"pivUseDefaultManagementKey":
MessageLookupByLibrary.simpleMessage("Use Default"),
"pollCanceled":
MessageLookupByLibrary.simpleMessage("No CanoKey is selected."),
"pollCanoKey": MessageLookupByLibrary.simpleMessage(
Expand Down Expand Up @@ -255,10 +272,13 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("WebUSB prompt when plug-in"),
"successfullyChanged":
MessageLookupByLibrary.simpleMessage("Successfully changed"),
"validationExactLength": m7,
"validationHexString": MessageLookupByLibrary.simpleMessage(
"Please input a valid hexadecimal string."),
"warning": MessageLookupByLibrary.simpleMessage("Warning"),
"webauthnClientPinNotSupported": MessageLookupByLibrary.simpleMessage(
"This key does not support WebAuthn PIN."),
"webauthnDelete": m7,
"webauthnDelete": m8,
"webauthnInputPinPrompt": MessageLookupByLibrary.simpleMessage(
"Please input your WebAuthn PIN."),
"webauthnInputPinTitle":
Expand Down
24 changes: 20 additions & 4 deletions lib/generated/intl/messages_zh_Hans.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ class MessageLookup extends MessageLookupByLibrary {

static String m6(applet) => "该操作将抹除 ${applet} 的全部数据!";

static String m7(name) => "您正在删除${name},删除该项目后无法恢复!请确认您有其他方式登录该服务。";
static String m7(length) => "需要 ${length} 个字符";

static String m8(name) => "您正在删除${name},删除该项目后无法恢复!请确认您有其他方式登录该服务。";

final messages = _notInlinedMessages(_notInlinedMessages);
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
Expand Down Expand Up @@ -110,7 +112,7 @@ class MessageLookup extends MessageLookupByLibrary {
"oathTooLong": MessageLookupByLibrary.simpleMessage("长度超限"),
"oathType": MessageLookupByLibrary.simpleMessage("类型"),
"off": MessageLookupByLibrary.simpleMessage("关"),
"oldPin": MessageLookupByLibrary.simpleMessage(" PIN"),
"oldPin": MessageLookupByLibrary.simpleMessage("当前 PIN"),
"on": MessageLookupByLibrary.simpleMessage("开"),
"openpgpAuthentication": MessageLookupByLibrary.simpleMessage("认证"),
"openpgpCardHolder": MessageLookupByLibrary.simpleMessage("持卡人"),
Expand Down Expand Up @@ -155,10 +157,21 @@ class MessageLookup extends MessageLookupByLibrary {
"pinInvalidLength": MessageLookupByLibrary.simpleMessage("长度错误"),
"pinLength": MessageLookupByLibrary.simpleMessage("输入的 PIN 长度错误"),
"pinRetries": m4,
"pivChangeManagementKey":
MessageLookupByLibrary.simpleMessage("修改管理密钥"),
"pivChangeManagementKeyPrompt": MessageLookupByLibrary.simpleMessage(
"新管理密钥的长度应当为 24 字节。请妥善保管管理密钥,否则您将无法管理 PIV 应用。"),
"pivChangePUK": MessageLookupByLibrary.simpleMessage("修改 PUK"),
"pivManagementKeyVerificationFailed":
MessageLookupByLibrary.simpleMessage("管理密钥验证失败"),
"pivNewManagementKey": MessageLookupByLibrary.simpleMessage("新密钥"),
"pivNewPUK": MessageLookupByLibrary.simpleMessage("新 PUK"),
"pivOldPUK": MessageLookupByLibrary.simpleMessage("旧 PUK"),
"pivOldManagementKey": MessageLookupByLibrary.simpleMessage("当前密钥"),
"pivOldPUK": MessageLookupByLibrary.simpleMessage("当前 PUK"),
"pivPinManagement": MessageLookupByLibrary.simpleMessage("管理 PIN"),
"pivRandomManagementKey": MessageLookupByLibrary.simpleMessage("随机密钥"),
"pivUseDefaultManagementKey":
MessageLookupByLibrary.simpleMessage("使用默认密钥"),
"pollCanceled": MessageLookupByLibrary.simpleMessage("您没有选择任何 CanoKey"),
"pollCanoKey":
MessageLookupByLibrary.simpleMessage("请点击右上角刷新按钮读取 CanoKey"),
Expand Down Expand Up @@ -209,10 +222,13 @@ class MessageLookup extends MessageLookupByLibrary {
MessageLookupByLibrary.simpleMessage("WebAuthn SM2"),
"settingsWebUSB": MessageLookupByLibrary.simpleMessage("插入时 WebUSB 提示"),
"successfullyChanged": MessageLookupByLibrary.simpleMessage("修改成功"),
"validationExactLength": m7,
"validationHexString":
MessageLookupByLibrary.simpleMessage("请输入十六进制字符串"),
"warning": MessageLookupByLibrary.simpleMessage("警告"),
"webauthnClientPinNotSupported":
MessageLookupByLibrary.simpleMessage("该密钥不支持 WebAuthn PIN。"),
"webauthnDelete": m7,
"webauthnDelete": m8,
"webauthnInputPinPrompt":
MessageLookupByLibrary.simpleMessage("请输入您的 WebAuthn PIN。"),
"webauthnInputPinTitle":
Expand Down
98 changes: 94 additions & 4 deletions lib/generated/l10n.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions lib/helper/utils/string_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,8 @@ class StringUtils {
static bool validateStringRange(String text, [int minLength = 8, int maxLength = 20]) {
return text.length >= minLength && text.length <= maxLength;
}

static bool isHex(String value) {
return RegExp(r'^[0-9a-fA-F]+$').hasMatch(value);
}
}
31 changes: 26 additions & 5 deletions lib/helper/widgets/validators.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:canokey_console/generated/l10n.dart';
import 'package:canokey_console/helper/utils/string_utils.dart';
import 'package:canokey_console/helper/widgets/field_validator.dart';
import 'package:get/get.dart';

class EmailValidator extends FieldValidatorRule<String> {
@override
Expand Down Expand Up @@ -45,10 +47,10 @@ class IntValidator extends FieldValidatorRule<String> {
}

class LengthValidator implements FieldValidatorRule<String> {
final bool short, required;
final bool required;
final int? min, max, exact;

LengthValidator({this.required = true, this.exact, this.min, this.max, this.short = false});
LengthValidator({this.required = true, this.exact, this.min, this.max});

@override
String? validate(String? value, bool required, Map<String, dynamic> data) {
Expand All @@ -57,13 +59,32 @@ class LengthValidator implements FieldValidatorRule<String> {
return null;
}
if (exact != null && value.length != exact!) {
return short ? "Need $exact characters" : "Need exact $exact characters";
return S.of(Get.context!).validationExactLength(exact!);
}
if (min != null && value.length < min!) {
return short ? "Need $min characters" : "Longer than $min characters";
return "Longer than $min characters";
}
if (max != null && value.length > max!) {
return short ? "Only $max characters" : "Lesser than $max characters";
return "Lesser than $max characters";
}
}
return null;
}
}

class HexStringValidator implements FieldValidatorRule<String> {
final bool required;

HexStringValidator({this.required = true});

@override
String? validate(String? value, bool required, Map<String, dynamic> data) {
if (value != null) {
if (!required && value.isEmpty) {
return null;
}
if (!StringUtils.isHex(value)) {
return S.of(Get.context!).validationHexString;
}
}
return null;
Expand Down
15 changes: 12 additions & 3 deletions lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"pinLength": "The provided PIN is too short or too long.",
"seconds": "seconds",
"change": "Change",
"oldPin": "Old PIN",
"oldPin": "Current PIN",
"newPin": "New PIN",
"actions": "Actions",
"cancel": "Cancel",
Expand Down Expand Up @@ -152,7 +152,16 @@
"webauthnPinBlocked": "PIN authentication is blocked. Please reset WebAuthn.",
"pivPinManagement": "PIN Management",
"pivChangePUK": "Change PUK",
"pivOldPUK": "Old PUK",
"pivOldPUK": "Current PUK",
"pivNewPUK": "New PUK",
"pivChangePUKPrompt": "New PUK should be at least {min} characters long. The maximum length is {max}."
"pivChangePUKPrompt": "New PUK should be at least {min} characters long. The maximum length is {max}.",
"pivChangeManagementKey": "Change Management Key",
"pivChangeManagementKeyPrompt": "New Management Key should be 24 bytes long. Please save it in a safe place.",
"pivOldManagementKey": "Current Management Key",
"pivNewManagementKey": "New Management Key",
"pivUseDefaultManagementKey": "Use Default",
"pivRandomManagementKey": "Random",
"pivManagementKeyVerificationFailed": "Management Key verification failed",
"validationHexString": "Please input a valid hexadecimal string.",
"validationExactLength": "Need exact {length} characters"
}
Loading

0 comments on commit 6abe4fd

Please sign in to comment.