Skip to content

Commit

Permalink
Verify that public key from cert matches private key
Browse files Browse the repository at this point in the history
  • Loading branch information
elibon99 committed Jan 31, 2025
1 parent 3968bd7 commit 5383a8f
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 45 deletions.
54 changes: 34 additions & 20 deletions helper/helper/piv.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,26 +262,6 @@ def reset(self):
def slots(self):
return SlotsNode(self.session)

@action(closes_child=False)
def examine_file(self, data: bytes, password: str | None = None):
try:
private_key, certs = _parse_file(data, password)
certificate = _choose_cert(certs)

return dict(
status=True,
password=password is not None,
key_type=(
KEY_TYPE.from_public_key(private_key.public_key())
if private_key
else None
),
cert_info=_get_cert_info(certificate),
)
except InvalidPasswordError:
logger.debug("Invalid or missing password", exc_info=True)
return dict(status=False)

@action(closes_child=False)
def validate_rfc4514(self, data: str):
try:
Expand Down Expand Up @@ -459,6 +439,40 @@ def move_key(
self._refresh()
return dict()

@action
def examine_file(self, data: bytes, password: str | None = None):
try:
private_key, certs = _parse_file(data, password)
certificate = _choose_cert(certs)

response = dict(
status=True,
password=password is not None,
key_type=(
KEY_TYPE.from_public_key(private_key.public_key())
if private_key
else None
),
cert_info=_get_cert_info(certificate),
)

if self.metadata and certificate and not private_key:
# Verify that the public key of a cert matches the
# private key in the slot
slot_public_key = self.metadata.public_key
cert_public_key = certificate.public_key()
public_key_match = slot_public_key.public_bytes(
encoding=Encoding.DER, format=PublicFormat.SubjectPublicKeyInfo
) == cert_public_key.public_bytes(
encoding=Encoding.DER, format=PublicFormat.SubjectPublicKeyInfo
)
response["public_key_match"] = public_key_match

return response
except InvalidPasswordError:
logger.debug("Invalid or missing password", exc_info=True)
return dict(status=False)

@action
def import_file(self, data: bytes, password: str | None = None, **kwargs):
try:
Expand Down
8 changes: 6 additions & 2 deletions lib/desktop/piv/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,12 @@ class _DesktopPivSlotsNotifier extends PivSlotsNotifier {
}

@override
Future<PivExamineResult> examine(String data, {String? password}) async {
final result = await _session.command('examine_file', params: {
Future<PivExamineResult> examine(SlotId slot, String data,
{String? password}) async {
final result = await _session.command('examine_file', target: [
'slots',
slot.hexId
], params: {
'data': data,
'password': password,
});
Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_de.arb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@
"slot": {}
}
},
"p_warning_public_key_mismatch": null,
"@p_warning_public_key_mismatch": {
"placeholders": {
"slot": {}
}
},
"l_key_moved": "Schlüssel verschoben",
"l_key_and_certificate_moved": "Schlüssel und Zertifikat verschoben",
"p_subject_desc": "Distinguished Name (DN) RFC 4514 konform formatiert.",
Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@
"slot": {}
}
},
"p_warning_public_key_mismatch": "The public key of the certificate does not match the private key in slot {slot}.",
"@p_warning_public_key_mismatch": {
"placeholders": {
"slot": {}
}
},
"l_key_moved": "Key moved",
"l_key_and_certificate_moved": "Key and certificate moved",
"p_subject_desc": "A distinguished name (DN) formatted in accordance to the RFC 4514 specification.",
Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@
"slot": {}
}
},
"p_warning_public_key_mismatch": null,
"@p_warning_public_key_mismatch": {
"placeholders": {
"slot": {}
}
},
"l_key_moved": "Clé déplacée",
"l_key_and_certificate_moved": "Clé et certificat déplacés",
"p_subject_desc": "DN (nom distinctif) formaté conformément à la spécification RFC 4514.",
Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_ja.arb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@
"slot": {}
}
},
"p_warning_public_key_mismatch": null,
"@p_warning_public_key_mismatch": {
"placeholders": {
"slot": {}
}
},
"l_key_moved": "キーを移動しました",
"l_key_and_certificate_moved": "キーと証明書が移動されました",
"p_subject_desc": "RFC 4514仕様に準拠した形式の識別名(DN)。",
Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@
"slot": {}
}
},
"p_warning_public_key_mismatch": null,
"@p_warning_public_key_mismatch": {
"placeholders": {
"slot": {}
}
},
"l_key_moved": "Klucz został przeniesiony",
"l_key_and_certificate_moved": "Klucz i certyfikat został przeniesiony",
"p_subject_desc": "Nazwa wyróżniająca (DN) sformatowana zgodnie ze specyfikacją RFC 4514.",
Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_sk.arb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@
"slot": {}
}
},
"p_warning_public_key_mismatch": null,
"@p_warning_public_key_mismatch": {
"placeholders": {
"slot": {}
}
},
"l_key_moved": "Kľúč bol presunutý",
"l_key_and_certificate_moved": "Kľúč a certifikát boli presunuté",
"p_subject_desc": "Rozlišujúci názov (DN) naformátovaný v súlade so špecifikáciou RFC 4514.",
Expand Down
6 changes: 6 additions & 0 deletions lib/l10n/app_vi.arb
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,12 @@
"slot": {}
}
},
"p_warning_public_key_mismatch": null,
"@p_warning_public_key_mismatch": {
"placeholders": {
"slot": {}
}
},
"l_key_moved": "Khóa đã được di chuyển",
"l_key_and_certificate_moved": "Khóa và chứng chỉ đã được di chuyển",
"p_subject_desc": "Tên phân biệt (DN) được định dạng theo tiêu chuẩn RFC 4514.",
Expand Down
1 change: 1 addition & 0 deletions lib/piv/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ class PivExamineResult with _$PivExamineResult {
required bool password,
required KeyType? keyType,
required CertInfo? certInfo,
bool? publicKeyMatch,
}) = _ExamineResult;
factory PivExamineResult.invalidPassword() = _InvalidPassword;

Expand Down
63 changes: 43 additions & 20 deletions lib/piv/models.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2365,22 +2365,24 @@ PivExamineResult _$PivExamineResultFromJson(Map<String, dynamic> json) {
mixin _$PivExamineResult {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
bool password, KeyType? keyType, CertInfo? certInfo)
required TResult Function(bool password, KeyType? keyType,
CertInfo? certInfo, bool? publicKeyMatch)
result,
required TResult Function() invalidPassword,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(bool password, KeyType? keyType, CertInfo? certInfo)?
TResult? Function(bool password, KeyType? keyType, CertInfo? certInfo,
bool? publicKeyMatch)?
result,
TResult? Function()? invalidPassword,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(bool password, KeyType? keyType, CertInfo? certInfo)?
TResult Function(bool password, KeyType? keyType, CertInfo? certInfo,
bool? publicKeyMatch)?
result,
TResult Function()? invalidPassword,
required TResult orElse(),
Expand Down Expand Up @@ -2437,7 +2439,11 @@ abstract class _$$ExamineResultImplCopyWith<$Res> {
_$ExamineResultImpl value, $Res Function(_$ExamineResultImpl) then) =
__$$ExamineResultImplCopyWithImpl<$Res>;
@useResult
$Res call({bool password, KeyType? keyType, CertInfo? certInfo});
$Res call(
{bool password,
KeyType? keyType,
CertInfo? certInfo,
bool? publicKeyMatch});

$CertInfoCopyWith<$Res>? get certInfo;
}
Expand All @@ -2458,6 +2464,7 @@ class __$$ExamineResultImplCopyWithImpl<$Res>
Object? password = null,
Object? keyType = freezed,
Object? certInfo = freezed,
Object? publicKeyMatch = freezed,
}) {
return _then(_$ExamineResultImpl(
password: null == password
Expand All @@ -2472,6 +2479,10 @@ class __$$ExamineResultImplCopyWithImpl<$Res>
? _value.certInfo
: certInfo // ignore: cast_nullable_to_non_nullable
as CertInfo?,
publicKeyMatch: freezed == publicKeyMatch
? _value.publicKeyMatch
: publicKeyMatch // ignore: cast_nullable_to_non_nullable
as bool?,
));
}

Expand All @@ -2497,6 +2508,7 @@ class _$ExamineResultImpl implements _ExamineResult {
{required this.password,
required this.keyType,
required this.certInfo,
this.publicKeyMatch,
final String? $type})
: $type = $type ?? 'result';

Expand All @@ -2509,13 +2521,15 @@ class _$ExamineResultImpl implements _ExamineResult {
final KeyType? keyType;
@override
final CertInfo? certInfo;
@override
final bool? publicKeyMatch;

@JsonKey(name: 'runtimeType')
final String $type;

@override
String toString() {
return 'PivExamineResult.result(password: $password, keyType: $keyType, certInfo: $certInfo)';
return 'PivExamineResult.result(password: $password, keyType: $keyType, certInfo: $certInfo, publicKeyMatch: $publicKeyMatch)';
}

@override
Expand All @@ -2527,12 +2541,15 @@ class _$ExamineResultImpl implements _ExamineResult {
other.password == password) &&
(identical(other.keyType, keyType) || other.keyType == keyType) &&
(identical(other.certInfo, certInfo) ||
other.certInfo == certInfo));
other.certInfo == certInfo) &&
(identical(other.publicKeyMatch, publicKeyMatch) ||
other.publicKeyMatch == publicKeyMatch));
}

@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType, password, keyType, certInfo);
int get hashCode =>
Object.hash(runtimeType, password, keyType, certInfo, publicKeyMatch);

/// Create a copy of PivExamineResult
/// with the given fields replaced by the non-null parameter values.
Expand All @@ -2545,34 +2562,36 @@ class _$ExamineResultImpl implements _ExamineResult {
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
bool password, KeyType? keyType, CertInfo? certInfo)
required TResult Function(bool password, KeyType? keyType,
CertInfo? certInfo, bool? publicKeyMatch)
result,
required TResult Function() invalidPassword,
}) {
return result(password, keyType, certInfo);
return result(password, keyType, certInfo, publicKeyMatch);
}

@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(bool password, KeyType? keyType, CertInfo? certInfo)?
TResult? Function(bool password, KeyType? keyType, CertInfo? certInfo,
bool? publicKeyMatch)?
result,
TResult? Function()? invalidPassword,
}) {
return result?.call(password, keyType, certInfo);
return result?.call(password, keyType, certInfo, publicKeyMatch);
}

@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(bool password, KeyType? keyType, CertInfo? certInfo)?
TResult Function(bool password, KeyType? keyType, CertInfo? certInfo,
bool? publicKeyMatch)?
result,
TResult Function()? invalidPassword,
required TResult orElse(),
}) {
if (result != null) {
return result(password, keyType, certInfo);
return result(password, keyType, certInfo, publicKeyMatch);
}
return orElse();
}
Expand Down Expand Up @@ -2620,14 +2639,16 @@ abstract class _ExamineResult implements PivExamineResult {
factory _ExamineResult(
{required final bool password,
required final KeyType? keyType,
required final CertInfo? certInfo}) = _$ExamineResultImpl;
required final CertInfo? certInfo,
final bool? publicKeyMatch}) = _$ExamineResultImpl;

factory _ExamineResult.fromJson(Map<String, dynamic> json) =
_$ExamineResultImpl.fromJson;

bool get password;
KeyType? get keyType;
CertInfo? get certInfo;
bool? get publicKeyMatch;

/// Create a copy of PivExamineResult
/// with the given fields replaced by the non-null parameter values.
Expand Down Expand Up @@ -2685,8 +2706,8 @@ class _$InvalidPasswordImpl implements _InvalidPassword {
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(
bool password, KeyType? keyType, CertInfo? certInfo)
required TResult Function(bool password, KeyType? keyType,
CertInfo? certInfo, bool? publicKeyMatch)
result,
required TResult Function() invalidPassword,
}) {
Expand All @@ -2696,7 +2717,8 @@ class _$InvalidPasswordImpl implements _InvalidPassword {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(bool password, KeyType? keyType, CertInfo? certInfo)?
TResult? Function(bool password, KeyType? keyType, CertInfo? certInfo,
bool? publicKeyMatch)?
result,
TResult? Function()? invalidPassword,
}) {
Expand All @@ -2706,7 +2728,8 @@ class _$InvalidPasswordImpl implements _InvalidPassword {
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(bool password, KeyType? keyType, CertInfo? certInfo)?
TResult Function(bool password, KeyType? keyType, CertInfo? certInfo,
bool? publicKeyMatch)?
result,
TResult Function()? invalidPassword,
required TResult orElse(),
Expand Down
2 changes: 2 additions & 0 deletions lib/piv/models.g.dart

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

Loading

0 comments on commit 5383a8f

Please sign in to comment.