Skip to content

Commit

Permalink
Remove schema checks in securesystemslib.gpg
Browse files Browse the repository at this point in the history
In preparation for the removal of schema.py (secure-systems-lab#183), this patch removes
schema checks in the following modules of the `securesystemslib.gpg`
subpackage:

* internal modules `rsa`, `dsa`, `eddsa`, `common`. These checks are
  redundant with schema checks that are already performed in the calling
  functions of the `functions` module.

* in previously public `functions` module: * keyid in `create_signature`
  and `export_pubkey` functions * public key and signature dict in
  `verify_signature` function

This is okay for two reasons:

1. the preferred way of interacting with
   `securesystemslib.gpg.functions` is via `GPGSigner`, which controls
   the format of the passed arguments to some extent

2. securesystemslib.gpg still raises meaningful and even more consistent
   errors for invalid arguments anyway, than it did before. E.g. a keyid
   passed to `export_pubkey` that doesn't conform to the previously
   checked hex schema, now raises a `KeyNotFoundError`.

Other changes include:

* move string literal `GPG_HASH_ALGORITHM_STRING` from
  `securesystemslib.schema` to the better suited
  `secureystemslib.gpg.constants` module.
* remove mentions of schema definitions in docstrings
* adopt changes in tests

Signed-off-by: Lukas Puehringer <[email protected]>
  • Loading branch information
lukpueh committed Apr 15, 2024
1 parent 420b38c commit 7d4c336
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 129 deletions.
22 changes: 7 additions & 15 deletions securesystemslib/gpg/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
import logging
import struct

from securesystemslib import formats
from securesystemslib.gpg import util as gpg_util
from securesystemslib.gpg.constants import (
FULL_KEYID_SUBPACKET,
GPG_HASH_ALGORITHM_STRING,
KEY_EXPIRATION_SUBPACKET,
PACKET_TYPE_PRIMARY_KEY,
PACKET_TYPE_SIGNATURE,
Expand Down Expand Up @@ -93,7 +93,7 @@ def parse_pubkey_payload(data):
None.
<Returns>
A public key in the format securesystemslib.formats.GPG_PUBKEY_SCHEMA
A public key dict.
"""
if not data:
Expand Down Expand Up @@ -145,7 +145,7 @@ def parse_pubkey_payload(data):
return {
"method": keyinfo["method"],
"type": keyinfo["type"],
"hashes": [formats.GPG_HASH_ALGORITHM_STRING],
"hashes": [GPG_HASH_ALGORITHM_STRING],
"creation_time": time_of_creation[0],
"keyid": keyinfo["keyid"],
"keyval": {"private": "", "public": key_params},
Expand Down Expand Up @@ -333,7 +333,7 @@ def _assign_certified_key_info(bundle):
None.
<Returns>
A public key in the format securesystemslib.formats.GPG_PUBKEY_SCHEMA.
A public key dict.
"""
# Create handler shortcut
Expand Down Expand Up @@ -476,8 +476,7 @@ def _get_verified_subkeys(bundle):
None.
<Returns>
A dictionary of public keys in the format
securesystemslib.formats.GPG_PUBKEY_SCHEMA, with keyids as dict keys.
A dict of public keys dicts with keyids as dict keys.
"""
# Create handler shortcut
Expand Down Expand Up @@ -601,19 +600,14 @@ def get_pubkey_bundle(data, keyid):
If no master key or subkeys could be found that matches the passed
keyid.
securesystemslib.exceptions.FormatError
If the passed keyid does not match
securesystemslib.formats.KEYID_SCHEMA
<Side Effects>
None.
<Returns>
A public key in the format securesystemslib.formats.GPG_PUBKEY_SCHEMA with
optional subkeys.
A public key dict with optional subkeys.
"""
formats.KEYID_SCHEMA.check_match(keyid)
if not data:
raise KeyNotFoundError(
"Could not find gpg key '{}' in empty exported key " # pylint: disable=consider-using-f-string
Expand Down Expand Up @@ -703,9 +697,7 @@ def parse_signature_packet( # pylint: disable=too-many-locals,too-many-branches
None.
<Returns>
A signature dictionary matching
securesystemslib.formats.GPG_SIGNATURE_SCHEMA with the following special
characteristics:
A signature dict with the following special characteristics:
- The "keyid" field is an empty string if it cannot be determined
- The "short_keyid" is not added if it cannot be determined
- At least one of non-empty "keyid" or "short_keyid" are part of the
Expand Down
2 changes: 2 additions & 0 deletions securesystemslib/gpg/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,5 @@ def gpg_export_pubkey_command(homearg: str, keyid: str) -> List[str]:
PRIMARY_USERID_SUBPACKET = 0x19
# See section 5.2.3.28. (Issuer Fingerprint) of rfc4880bis-06
FULL_KEYID_SUBPACKET = 0x21

GPG_HASH_ALGORITHM_STRING = "pgp+SHA2"
26 changes: 5 additions & 21 deletions securesystemslib/gpg/dsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
CRYPTO = False

# pylint: disable=wrong-import-position
from securesystemslib import exceptions, formats
from securesystemslib import exceptions
from securesystemslib.gpg import util as gpg_util
from securesystemslib.gpg.exceptions import PacketParsingError

Expand All @@ -43,13 +43,9 @@ def create_pubkey(pubkey_info):
<Arguments>
pubkey_info:
The DSA pubkey info dictionary as specified by
securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
The DSA pubkey dict.
<Exceptions>
securesystemslib.exceptions.FormatError if
pubkey_info does not match securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if
the cryptography module is not available
Expand All @@ -61,8 +57,6 @@ def create_pubkey(pubkey_info):
if not CRYPTO: # pragma: no cover
raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

formats.GPG_DSA_PUBKEY_SCHEMA.check_match(pubkey_info)

y = int(pubkey_info["keyval"]["public"]["y"], 16)
g = int(pubkey_info["keyval"]["public"]["g"], 16)
p = int(pubkey_info["keyval"]["public"]["p"], 16)
Expand Down Expand Up @@ -93,8 +87,7 @@ def get_pubkey_params(data):
None.
<Returns>
The parsed DSA public key in the format
securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA.
A DSA public key dict.
"""
ptr = 0
Expand Down Expand Up @@ -190,12 +183,10 @@ def verify_signature(signature_object, pubkey_info, content, hash_algorithm_id):
<Arguments>
signature_object:
A signature dictionary as specified by
securesystemslib.formats.GPG_SIGNATURE_SCHEMA
A signature dict.
pubkey_info:
The DSA public key info dictionary as specified by
securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
The DSA public key dict.
hash_algorithm_id:
one of SHA1, SHA256, SHA512 (see securesystemslib.gpg.constants)
Expand All @@ -207,10 +198,6 @@ def verify_signature(signature_object, pubkey_info, content, hash_algorithm_id):
The signed bytes against which the signature is verified
<Exceptions>
securesystemslib.exceptions.FormatError if:
signature_object does not match securesystemslib.formats.GPG_SIGNATURE_SCHEMA
pubkey_info does not match securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if:
the cryptography module is not available
Expand All @@ -225,9 +212,6 @@ def verify_signature(signature_object, pubkey_info, content, hash_algorithm_id):
if not CRYPTO: # pragma: no cover
raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

formats.GPG_SIGNATURE_SCHEMA.check_match(signature_object)
formats.GPG_DSA_PUBKEY_SCHEMA.check_match(pubkey_info)

hasher = gpg_util.get_hashing_class(hash_algorithm_id)

pubkey_object = create_pubkey(pubkey_info)
Expand Down
25 changes: 5 additions & 20 deletions securesystemslib/gpg/eddsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import binascii

from securesystemslib import exceptions, formats
from securesystemslib import exceptions
from securesystemslib.gpg import util as gpg_util
from securesystemslib.gpg.exceptions import PacketParsingError

Expand Down Expand Up @@ -65,8 +65,7 @@ def get_pubkey_params(data):
<Returns>
A dictionary with an element "q" that holds the ascii hex representation
of the MPI of an EC point representing an EdDSA public key that conforms
with securesystemslib.formats.GPG_ED25519_PUBKEY_SCHEMA.
of the MPI of an EC point representing an EdDSA public key.
"""
ptr = 0
Expand Down Expand Up @@ -163,12 +162,9 @@ def create_pubkey(pubkey_info):
<Arguments>
pubkey_info:
The ED25519 public key dictionary as specified by
securesystemslib.formats.GPG_ED25519_PUBKEY_SCHEMA
The ED25519 public key dict.
<Exceptions>
securesystemslib.exceptions.FormatError if
pubkey_info does not match securesystemslib.formats.GPG_DSA_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if
the cryptography module is unavailable
Expand All @@ -181,8 +177,6 @@ def create_pubkey(pubkey_info):
if not CRYPTO: # pragma: no cover
raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

formats.GPG_ED25519_PUBKEY_SCHEMA.check_match(pubkey_info)

public_bytes = binascii.unhexlify(pubkey_info["keyval"]["public"]["q"])
public_key = pyca_ed25519.Ed25519PublicKey.from_public_bytes(public_bytes)

Expand All @@ -197,12 +191,10 @@ def verify_signature(signature_object, pubkey_info, content, hash_algorithm_id):
<Arguments>
signature_object:
A signature dictionary as specified by
securesystemslib.formats.GPG_SIGNATURE_SCHEMA
A signature dict.
pubkey_info:
The DSA public key info dictionary as specified by
securesystemslib.formats.GPG_ED25519_PUBKEY_SCHEMA
A DSA public key dict.
hash_algorithm_id:
one of SHA1, SHA256, SHA512 (see securesystemslib.gpg.constants)
Expand All @@ -214,10 +206,6 @@ def verify_signature(signature_object, pubkey_info, content, hash_algorithm_id):
The signed bytes against which the signature is verified
<Exceptions>
securesystemslib.exceptions.FormatError if:
signature_object does not match securesystemslib.formats.GPG_SIGNATURE_SCHEMA
pubkey_info does not match securesystemslib.formats.GPG_ED25519_PUBKEY_SCHEMA
securesystemslib.exceptions.UnsupportedLibraryError if:
the cryptography module is unavailable
Expand All @@ -232,9 +220,6 @@ def verify_signature(signature_object, pubkey_info, content, hash_algorithm_id):
if not CRYPTO: # pragma: no cover
raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

formats.GPG_SIGNATURE_SCHEMA.check_match(signature_object)
formats.GPG_ED25519_PUBKEY_SCHEMA.check_match(pubkey_info)

hasher = gpg_util.get_hashing_class(hash_algorithm_id)

pubkey_object = create_pubkey(pubkey_info)
Expand Down
35 changes: 8 additions & 27 deletions securesystemslib/gpg/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import subprocess # nosec
import time

from securesystemslib import exceptions, formats
from securesystemslib import exceptions
from securesystemslib.gpg.common import (
get_pubkey_bundle,
parse_signature_packet,
Expand Down Expand Up @@ -73,9 +73,6 @@ def create_signature(content, keyid=None, homedir=None, timeout=GPG_TIMEOUT):
gpg command timeout in seconds. Default is 10.
<Exceptions>
securesystemslib.exceptions.FormatError:
If the keyid was passed and does not match
securesystemslib.formats.KEYID_SCHEMA
ValueError:
If the gpg command failed to create a valid signature.
Expand All @@ -98,8 +95,7 @@ def create_signature(content, keyid=None, homedir=None, timeout=GPG_TIMEOUT):
None.
<Returns>
The created signature in the format:
securesystemslib.formats.GPG_SIGNATURE_SCHEMA.
A signature dict.
"""
if not have_gpg(): # pragma: no cover
Expand All @@ -110,7 +106,6 @@ def create_signature(content, keyid=None, homedir=None, timeout=GPG_TIMEOUT):

keyarg = ""
if keyid:
formats.KEYID_SCHEMA.check_match(keyid)
keyarg = (
"--local-user {}".format( # pylint: disable=consider-using-f-string
keyid
Expand Down Expand Up @@ -211,12 +206,10 @@ def verify_signature(signature_object, pubkey_info, content):
<Arguments>
signature_object:
A signature object in the format:
securesystemslib.formats.GPG_SIGNATURE_SCHEMA
A signature dict.
pubkey_info:
A public key object in the format:
securesystemslib.formats.GPG_PUBKEY_SCHEMA
A public key dict.
content:
The content to be verified. (bytes)
Expand All @@ -238,9 +231,6 @@ def verify_signature(signature_object, pubkey_info, content):
if not CRYPTO: # pragma: no cover
raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

formats.GPG_PUBKEY_SCHEMA.check_match(pubkey_info)
formats.GPG_SIGNATURE_SCHEMA.check_match(signature_object)

handler = SIGNATURE_HANDLERS[pubkey_info["type"]]
sig_keyid = signature_object["keyid"]

Expand Down Expand Up @@ -270,13 +260,12 @@ def export_pubkey(keyid, homedir=None, timeout=GPG_TIMEOUT):
"""Exports a public key from a GnuPG keyring.
Arguments:
keyid: An OpenPGP keyid in KEYID_SCHEMA format.
keyid: An OpenPGP keyid..
homedir (optional): A path to the GnuPG home directory. If not set the
default GnuPG home directory is used.
timeout (optional): gpg command timeout in seconds. Default is 10.
Raises:
ValueError: Keyid is not a string.
UnsupportedLibraryError: The gpg command or pyca/cryptography are not
available.
KeyNotFoundError: No key or subkey was found for that keyid.
Expand All @@ -285,7 +274,7 @@ def export_pubkey(keyid, homedir=None, timeout=GPG_TIMEOUT):
Calls system gpg command in a subprocess.
Returns:
An OpenPGP public key object in GPG_PUBKEY_SCHEMA format.
An OpenPGP public key dict.
"""
if not have_gpg(): # pragma: no cover
Expand All @@ -294,14 +283,6 @@ def export_pubkey(keyid, homedir=None, timeout=GPG_TIMEOUT):
if not CRYPTO: # pragma: no cover
raise exceptions.UnsupportedLibraryError(NO_CRYPTO_MSG)

if not formats.KEYID_SCHEMA.matches(keyid):
# FIXME: probably needs smarter parsing of what a valid keyid is so as to
# not export more than one pubkey packet.
raise ValueError(
"we need to export an individual key. Please provide a " # pylint: disable=consider-using-f-string
" valid keyid! Keyid was '{}'.".format(keyid)
)

homearg = ""
if homedir:
homearg = (
Expand Down Expand Up @@ -330,7 +311,7 @@ def export_pubkeys(keyids, homedir=None, timeout=GPG_TIMEOUT):
"""Exports multiple public keys from a GnuPG keyring.
Arguments:
keyids: A list of OpenPGP keyids in KEYID_SCHEMA format.
keyids: A list of OpenPGP keyids.
homedir (optional): A path to the GnuPG home directory. If not set the
default GnuPG home directory is used.
timeout (optional): gpg command timeout in seconds. Default is 10.
Expand All @@ -346,7 +327,7 @@ def export_pubkeys(keyids, homedir=None, timeout=GPG_TIMEOUT):
Calls system gpg command in a subprocess.
Returns:
A dict of OpenPGP public key objects in GPG_PUBKEY_SCHEMA format as values,
A dict of OpenPGP public key dicts as values,
and their keyids as dict keys.
Expand Down
Loading

0 comments on commit 7d4c336

Please sign in to comment.