keyringctl: Write User IDs to separate files
keyringctl: Add `persist_uids()` to write User ID related packets: User-ID and PositiveCertifications (UID binding signatures). Rename `persist_basic_key()` to `persist_public_key()` and change it to only persist the PublicKey packet. Change `persist_{certifications,revocations}()` to persist the certificates to a key-specific 'uids' subdirectory per PublicKey. Change `convert_certificate()` to rename `uid_binding_sig` to `uid_bind_sigs`. Simplify the logic for signature related data assignments.
This commit is contained in:
parent
7e04c50a16
commit
3c31230eb2
105
keyringctl
105
keyringctl
@ -84,7 +84,7 @@ def convert_certificate(working_dir: Path, certificate: Path, name_override: Opt
|
||||
current_packet_mode: Optional[str] = None
|
||||
current_packet_key: Optional[str] = None
|
||||
uids: Dict[str, Path] = {}
|
||||
uid_binding_sig: Dict[str, Path] = {}
|
||||
uid_binding_sigs: Dict[str, Path] = {}
|
||||
subkeys: Dict[str, Dict[str, Path]] = {}
|
||||
subkey_binding_sigs: Dict[str, Dict[str, Path]] = {}
|
||||
subkey_revocations: Dict[str, Dict[str, Path]] = {}
|
||||
@ -134,8 +134,7 @@ def convert_certificate(working_dir: Path, certificate: Path, name_override: Opt
|
||||
current_packet_mode = 'pubkey'
|
||||
current_packet_key = certificate_fingerprint
|
||||
elif packet.name.endswith('--UserID'):
|
||||
value = packet_dump_field(packet, 'Value')
|
||||
value = simplify_user_id(value)
|
||||
value = simplify_user_id(packet_dump_field(packet, 'Value'))
|
||||
current_packet_mode = 'uid'
|
||||
current_packet_key = value
|
||||
uids[value] = packet
|
||||
@ -161,51 +160,30 @@ def convert_certificate(working_dir: Path, certificate: Path, name_override: Opt
|
||||
issuer = packet_dump_field(packet, 'Issuer')
|
||||
signature_type = packet_dump_field(packet, 'Type')
|
||||
|
||||
if signature_type == 'DirectKey':
|
||||
direct_sigs = add_packet_to_direct_sigs(
|
||||
direct_sigs=direct_sigs,
|
||||
issuer=issuer,
|
||||
packet_key=current_packet_key,
|
||||
packet=packet,
|
||||
)
|
||||
continue
|
||||
|
||||
if not current_packet_key:
|
||||
# TODO GenericCertification PersonaCertification CasualCertification PositiveCertification
|
||||
raise Exception(f'unknown packet key for "{packet.name}"')
|
||||
|
||||
if current_packet_mode == 'uid' or current_packet_mode == 'pubkey':
|
||||
if certificate_fingerprint.endswith(issuer):
|
||||
if signature_type == 'PositiveCertification':
|
||||
uid_binding_sig[current_packet_key] = packet
|
||||
elif signature_type == 'CertificationRevocation':
|
||||
revocations[current_packet_key].append(packet)
|
||||
elif signature_type == 'KeyRevocation':
|
||||
if current_packet_mode == 'pubkey':
|
||||
if signature_type == 'KeyRevocation' and certificate_fingerprint.endswith(issuer):
|
||||
direct_revocations = add_packet_to_direct_sigs(
|
||||
direct_sigs=direct_revocations,
|
||||
issuer=issuer,
|
||||
packet_key=current_packet_key,
|
||||
packet=packet,
|
||||
)
|
||||
else:
|
||||
raise Exception(f'unknown signature type: {signature_type}')
|
||||
else:
|
||||
if signature_type.endswith('Certification'):
|
||||
# NOTE: here we are only considering signatures directly on the root key
|
||||
# signatures on a User ID, that are not tied to it via a SubkeyBinding are not addressed
|
||||
if current_packet_key not in uids:
|
||||
elif signature_type in ['DirectKey', 'GenericCertification']:
|
||||
direct_sigs = add_packet_to_direct_sigs(
|
||||
direct_sigs=direct_sigs,
|
||||
issuer=issuer,
|
||||
packet_key=current_packet_key,
|
||||
packet=packet,
|
||||
)
|
||||
# NOTE: here we address all signatures on User IDs (those that are tied to it with a
|
||||
# SubkeyBinding and those that are not)
|
||||
else:
|
||||
certifications[current_packet_key].append(packet)
|
||||
elif signature_type == 'CertificationRevocation':
|
||||
raise Exception(f'unknown signature type: {signature_type}')
|
||||
elif current_packet_mode == 'uid':
|
||||
if signature_type == 'CertificationRevocation':
|
||||
revocations[current_packet_key].append(packet)
|
||||
elif signature_type == 'PositiveCertification' and certificate_fingerprint.endswith(issuer):
|
||||
uid_binding_sigs[current_packet_key] = packet
|
||||
elif signature_type.endswith('Certification'):
|
||||
certifications[current_packet_key].append(packet)
|
||||
else:
|
||||
raise Exception(f'unknown signature type: {signature_type}')
|
||||
elif current_packet_mode == 'subkey':
|
||||
@ -236,11 +214,15 @@ def convert_certificate(working_dir: Path, certificate: Path, name_override: Opt
|
||||
key_dir = (user_dir / certificate_fingerprint)
|
||||
key_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
persist_basic_key(
|
||||
persist_public_key(
|
||||
certificate_fingerprint=certificate_fingerprint,
|
||||
pubkey=pubkey,
|
||||
key_dir=key_dir,
|
||||
uid_binding_sig=uid_binding_sig,
|
||||
)
|
||||
|
||||
persist_uids(
|
||||
key_dir=key_dir,
|
||||
uid_binding_sigs=uid_binding_sigs,
|
||||
uids=uids,
|
||||
)
|
||||
|
||||
@ -274,7 +256,7 @@ def convert_certificate(working_dir: Path, certificate: Path, name_override: Opt
|
||||
certifications=certifications,
|
||||
pubkey=pubkey,
|
||||
key_dir=key_dir,
|
||||
uid_binding_sig=uid_binding_sig,
|
||||
uid_binding_sig=uid_binding_sigs,
|
||||
uids=uids,
|
||||
)
|
||||
|
||||
@ -282,25 +264,19 @@ def convert_certificate(working_dir: Path, certificate: Path, name_override: Opt
|
||||
pubkey=pubkey,
|
||||
revocations=revocations,
|
||||
key_dir=key_dir,
|
||||
uid_binding_sig=uid_binding_sig,
|
||||
uid_binding_sig=uid_binding_sigs,
|
||||
uids=uids,
|
||||
)
|
||||
|
||||
return user_dir
|
||||
|
||||
|
||||
def persist_basic_key(
|
||||
def persist_public_key(
|
||||
certificate_fingerprint: str,
|
||||
pubkey: Path,
|
||||
key_dir: Path,
|
||||
uid_binding_sig: Dict[str, Path],
|
||||
uids: Dict[str, Path],
|
||||
) -> None:
|
||||
"""Persist the basic key material of a root key to file
|
||||
|
||||
The basic key material consists of the root key's public key, any PublicSubkeys and their SubkeyBindings, all User
|
||||
IDs and the per User ID PositiveCertifications.
|
||||
The file is written to key_dir and is named after the root key's certificate fingerprint.
|
||||
"""Persist the Public-Key packet
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -310,17 +286,38 @@ def persist_basic_key(
|
||||
The path to the public key of the root key
|
||||
key_dir: Path
|
||||
The root directory below which the basic key material is persisted
|
||||
uid_binding_sig: Dict[str, Path]
|
||||
"""
|
||||
|
||||
packets: List[Path] = [pubkey]
|
||||
output_file = key_dir / f'{certificate_fingerprint}.asc'
|
||||
debug(f'Writing file {output_file} from {[str(packet) for packet in packets]}')
|
||||
packet_join(packets, output_file)
|
||||
|
||||
|
||||
def persist_uids(
|
||||
key_dir: Path,
|
||||
uid_binding_sigs: Dict[str, Path],
|
||||
uids: Dict[str, Path],
|
||||
) -> None:
|
||||
"""Persist the User IDs that belong to a PublicKey
|
||||
|
||||
The User ID material consists of PublicSubkeys and their SubkeyBindings.
|
||||
The files are written to a UID specific directory and file below key_dir/uids.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
key_dir: Path
|
||||
The root directory below which the basic key material is persisted
|
||||
uid_binding_sigs: Dict[str, Path]
|
||||
The PositiveCertifications of a User ID and Public-Key packet
|
||||
uids: Dict[str, Path]
|
||||
The User IDs of a Public-Key (the root key)
|
||||
"""
|
||||
|
||||
packets: List[Path] = [pubkey]
|
||||
for key in uid_binding_sig.keys():
|
||||
packets.extend([uids[key], uid_binding_sig[key]])
|
||||
|
||||
output_file = key_dir / f'{certificate_fingerprint}.asc'
|
||||
for key in uid_binding_sigs.keys():
|
||||
packets = [uids[key], uid_binding_sigs[key]]
|
||||
output_file = key_dir / f'uids/{key}/{key}.asc'
|
||||
(key_dir / Path(f'uids/{key}')).mkdir(parents=True, exist_ok=True)
|
||||
debug(f'Writing file {output_file} from {[str(packet) for packet in packets]}')
|
||||
packet_join(packets, output_file)
|
||||
|
||||
@ -441,7 +438,7 @@ def persist_certifications(
|
||||
|
||||
for key, current_certifications in certifications.items():
|
||||
for certification in current_certifications:
|
||||
certification_dir = key_dir / key / 'certification'
|
||||
certification_dir = key_dir / Path("uids") / key / 'certification'
|
||||
certification_dir.mkdir(parents=True, exist_ok=True)
|
||||
issuer = packet_dump_field(certification, 'Issuer')
|
||||
|
||||
@ -479,7 +476,7 @@ def persist_revocations(
|
||||
|
||||
for key, current_revocations in revocations.items():
|
||||
for revocation in current_revocations:
|
||||
revocation_dir = key_dir / key / 'revocation'
|
||||
revocation_dir = key_dir / Path("uids") / key / 'revocation'
|
||||
revocation_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
issuer = packet_dump_field(revocation, 'Issuer')
|
||||
|
Loading…
Reference in New Issue
Block a user