-
Notifications
You must be signed in to change notification settings - Fork 50
Description
The following are currently suppressed linter errors, these should be reviewed and decided on if they can be resolved or kept suppressed with #noqa
.
This issue will be updated with more errors if when they come up.
PLW2901: redefined-loop-name
https://github.com/secure-systems-lab/securesystemslib/blob/db0a9a5afe9604f4e614e1979d0559832df64a08/securesystemslib/dsse.py#L63C1-L73C54
S603: subprocess-without-shell-equals-true
securesystemslib/securesystemslib/_gpg/constants.py
Lines 37 to 45 in db0a9a5
gpg_version_cmd = shlex.split(f"{gnupg} --version") | |
try: | |
subprocess.run( | |
gpg_version_cmd, # noqa: S603 | |
capture_output=True, | |
timeout=timeout, | |
check=True, | |
) | |
return True |
N818: error-suffix-on-exception-name
move this to exceptions.py
?
securesystemslib/securesystemslib/signer/_azure_signer.py
Lines 36 to 37 in db0a9a5
class UnsupportedKeyType(Exception): # noqa: N818 | |
pass |
PLR2004: magic-value-comparison
https://github.com/secure-systems-lab/securesystemslib/blob/db0a9a5afe9604f4e614e1979d0559832df64a08/securesystemslib/_gpg/util.py
https://github.com/secure-systems-lab/securesystemslib/blob/db0a9a5afe9604f4e614e1979d0559832df64a08/tests/test_gpg.py
PLW0603: global-statement
global _PYKCS11LIB # noqa: PLW0603 |
PLR0912: too-many-branches
securesystemslib/securesystemslib/_gpg/common.py
Lines 656 to 902 in db0a9a5
# ruff: noqa: PLR0912, PLR0915 | |
def parse_signature_packet( | |
data, | |
supported_signature_types=None, | |
supported_hash_algorithms=None, | |
include_info=False, | |
): | |
""" | |
<Purpose> | |
Parse the signature information on an RFC4880-encoded binary signature data | |
buffer. | |
NOTE: Older gpg versions (< FULLY_SUPPORTED_MIN_VERSION) might only | |
reveal the partial key id. It is the callers responsibility to determine | |
the full keyid based on the partial keyid, e.g. by exporting the related | |
public and replacing the partial keyid with the full keyid. | |
<Arguments> | |
data: | |
the RFC4880-encoded binary signature data buffer as described in | |
section 5.2 (and 5.2.3.1). | |
supported_signature_types: (optional) | |
a set of supported signature_types, the signature packet may be | |
(see securesystemslib._gpg.constants for available types). If None is | |
specified the signature packet must be of type SIGNATURE_TYPE_BINARY. | |
supported_hash_algorithms: (optional) | |
a set of supported hash algorithm ids, the signature packet | |
may use. Available ids are SHA1, SHA256, SHA512 (see | |
securesystemslib._gpg.constants). If None is specified, the signature | |
packet must use SHA256. | |
include_info: (optional) | |
a boolean that indicates whether an opaque dictionary should be | |
added to the returned signature under the key "info". Default is | |
False. | |
<Exceptions> | |
ValueError: if the signature packet is not supported or the data is | |
malformed | |
IndexError: if the signature packet is incomplete | |
<Side Effects> | |
None. | |
<Returns> | |
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 | |
signature | |
""" | |
if not supported_signature_types: | |
supported_signature_types = {SIGNATURE_TYPE_BINARY} | |
if not supported_hash_algorithms: | |
supported_hash_algorithms = {SHA256} | |
_, header_len, _, packet_len = gpg_util.parse_packet_header( | |
data, PACKET_TYPE_SIGNATURE | |
) | |
data = bytearray(data[header_len:packet_len]) | |
ptr = 0 | |
# we get the version number, which we also expect to be v4, or we bail | |
# FIXME: support v3 type signatures (which I haven't seen in the wild) | |
version_number = data[ptr] | |
ptr += 1 | |
if version_number not in SUPPORTED_SIGNATURE_PACKET_VERSIONS: | |
raise ValueError( | |
"Signature version '{}' not supported, must be one of " | |
"{}.".format(version_number, SUPPORTED_SIGNATURE_PACKET_VERSIONS) | |
) | |
# Per default we only parse "signatures of a binary document". Other types | |
# may be allowed by passing type constants via `supported_signature_types`. | |
# Types include revocation signatures, key binding signatures, persona | |
# certifications, etc. (see RFC 4880 section 5.2.1.). | |
signature_type = data[ptr] | |
ptr += 1 | |
if signature_type not in supported_signature_types: | |
raise ValueError( | |
"Signature type '{}' not supported, must be one of {} " | |
"(see RFC4880 5.2.1. Signature Types).".format( | |
signature_type, supported_signature_types | |
) | |
) | |
signature_algorithm = data[ptr] | |
ptr += 1 | |
if signature_algorithm not in SUPPORTED_SIGNATURE_ALGORITHMS: | |
raise ValueError( | |
"Signature algorithm '{}' not " | |
"supported, please verify that your gpg configuration is creating " | |
"either DSA, RSA, or EdDSA signatures (see RFC4880 9.1. Public-Key " | |
"Algorithms).".format(signature_algorithm) | |
) | |
key_type = SUPPORTED_SIGNATURE_ALGORITHMS[signature_algorithm]["type"] | |
handler = SIGNATURE_HANDLERS[key_type] | |
hash_algorithm = data[ptr] | |
ptr += 1 | |
if hash_algorithm not in supported_hash_algorithms: | |
raise ValueError( | |
"Hash algorithm '{}' not supported, must be one of {}" | |
" (see RFC4880 9.4. Hash Algorithms).".format( | |
hash_algorithm, supported_hash_algorithms | |
) | |
) | |
# Obtain the hashed octets | |
hashed_octet_count = struct.unpack(">H", data[ptr : ptr + 2])[0] | |
ptr += 2 | |
hashed_subpackets = data[ptr : ptr + hashed_octet_count] | |
hashed_subpacket_info = gpg_util.parse_subpackets(hashed_subpackets) | |
# Check whether we were actually able to read this much hashed octets | |
if len(hashed_subpackets) != hashed_octet_count: # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted." | |
"It is missing hashed octets!" | |
) | |
ptr += hashed_octet_count | |
other_headers_ptr = ptr | |
unhashed_octet_count = struct.unpack(">H", data[ptr : ptr + 2])[0] | |
ptr += 2 | |
unhashed_subpackets = data[ptr : ptr + unhashed_octet_count] | |
unhashed_subpacket_info = gpg_util.parse_subpackets(unhashed_subpackets) | |
ptr += unhashed_octet_count | |
# Use the info dict to return further signature information that may be | |
# needed for intermediate processing, but does not have to be on the eventual | |
# signature datastructure | |
info = { | |
"signature_type": signature_type, | |
"hash_algorithm": hash_algorithm, | |
"creation_time": None, | |
"subpackets": {}, | |
} | |
keyid = "" | |
short_keyid = "" | |
# Parse "Issuer" (short keyid) and "Issuer Fingerprint" (full keyid) type | |
# subpackets | |
# Strategy: Loop over all unhashed and hashed subpackets (in that order!) and | |
# store only the last of a type. Due to the order in the loop, hashed | |
# subpackets are prioritized over unhashed subpackets (see NOTEs below). | |
# NOTE: A subpacket may be found either in the hashed or unhashed subpacket | |
# sections of a signature. If a subpacket is not hashed, then the information | |
# in it cannot be considered definitive because it is not part of the | |
# signature proper. (see RFC4880 5.2.3.2.) | |
# NOTE: Signatures may contain conflicting information in subpackets. In most | |
# cases, an implementation SHOULD use the last subpacket, but MAY use any | |
# conflict resolution scheme that makes more sense. (see RFC4880 5.2.4.1.) | |
for idx, subpacket_tuple in enumerate( | |
unhashed_subpacket_info + hashed_subpacket_info | |
): | |
# The idx indicates if the info is from the unhashed (first) or | |
# hashed (second) of the above concatenated lists | |
is_hashed = idx >= len(unhashed_subpacket_info) | |
subpacket_type, subpacket_data = subpacket_tuple | |
# Warn if expiration subpacket is not hashed | |
if subpacket_type == KEY_EXPIRATION_SUBPACKET: | |
if not is_hashed: | |
log.warning( | |
"Expiration subpacket not hashed, gpg client possibly " | |
"exporting a weakly configured key." | |
) | |
# Full keyids are only available in newer signatures | |
# (see RFC4880 and rfc4880bis-06 5.2.3.1.) | |
if subpacket_type == FULL_KEYID_SUBPACKET: # pragma: no cover | |
# Exclude from coverage for consistent results across test envs | |
# NOTE: The first byte of the subpacket payload is a version number | |
# (see rfc4880bis-06 5.2.3.28.) | |
keyid = binascii.hexlify(subpacket_data[1:]).decode("ascii") | |
# We also return the short keyid, because the full might not be available | |
if subpacket_type == PARTIAL_KEYID_SUBPACKET: | |
short_keyid = binascii.hexlify(subpacket_data).decode("ascii") | |
if subpacket_type == SIG_CREATION_SUBPACKET: | |
info["creation_time"] = struct.unpack(">I", subpacket_data)[0] | |
info["subpackets"][subpacket_type] = subpacket_data | |
# Fail if there is no keyid at all (this should not happen) | |
if not (keyid or short_keyid): # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted. It does " | |
"not have an 'Issuer' or 'Issuer Fingerprint' subpacket (see RFC4880 " | |
"and rfc4880bis-06 5.2.3.1. Signature Subpacket Specification)." | |
) | |
# Fail if keyid and short keyid are specified but don't match | |
if keyid and not keyid.endswith(short_keyid): # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted. The key ID " | |
"'{}' of the 'Issuer' subpacket must match the lower 64 bits of the " | |
"fingerprint '{}' of the 'Issuer Fingerprint' subpacket (see RFC4880 " | |
"and rfc4880bis-06 5.2.3.28. Issuer Fingerprint).".format( | |
short_keyid, keyid | |
) | |
) | |
if not info["creation_time"]: # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted. It does " | |
"not have a 'Signature Creation Time' subpacket (see RFC4880 5.2.3.4 " | |
"Signature Creation Time)." | |
) | |
# Uncomment this variable to obtain the left-hash-bits information (used for | |
# early rejection) | |
# left_hash_bits = struct.unpack(">H", data[ptr:ptr+2])[0] | |
ptr += 2 | |
# Finally, fetch the actual signature (as opposed to signature metadata). | |
signature = handler.get_signature_params(data[ptr:]) | |
signature_data = { | |
"keyid": "{}".format(keyid), | |
"other_headers": binascii.hexlify(data[:other_headers_ptr]).decode( | |
"ascii" | |
), | |
"signature": binascii.hexlify(signature).decode("ascii"), | |
} | |
if short_keyid: # pragma: no branch | |
signature_data["short_keyid"] = short_keyid | |
if include_info: | |
signature_data["info"] = info | |
return signature_data |
PLR0915: too-many-statements
securesystemslib/securesystemslib/_gpg/common.py
Lines 656 to 902 in db0a9a5
# ruff: noqa: PLR0912, PLR0915 | |
def parse_signature_packet( | |
data, | |
supported_signature_types=None, | |
supported_hash_algorithms=None, | |
include_info=False, | |
): | |
""" | |
<Purpose> | |
Parse the signature information on an RFC4880-encoded binary signature data | |
buffer. | |
NOTE: Older gpg versions (< FULLY_SUPPORTED_MIN_VERSION) might only | |
reveal the partial key id. It is the callers responsibility to determine | |
the full keyid based on the partial keyid, e.g. by exporting the related | |
public and replacing the partial keyid with the full keyid. | |
<Arguments> | |
data: | |
the RFC4880-encoded binary signature data buffer as described in | |
section 5.2 (and 5.2.3.1). | |
supported_signature_types: (optional) | |
a set of supported signature_types, the signature packet may be | |
(see securesystemslib._gpg.constants for available types). If None is | |
specified the signature packet must be of type SIGNATURE_TYPE_BINARY. | |
supported_hash_algorithms: (optional) | |
a set of supported hash algorithm ids, the signature packet | |
may use. Available ids are SHA1, SHA256, SHA512 (see | |
securesystemslib._gpg.constants). If None is specified, the signature | |
packet must use SHA256. | |
include_info: (optional) | |
a boolean that indicates whether an opaque dictionary should be | |
added to the returned signature under the key "info". Default is | |
False. | |
<Exceptions> | |
ValueError: if the signature packet is not supported or the data is | |
malformed | |
IndexError: if the signature packet is incomplete | |
<Side Effects> | |
None. | |
<Returns> | |
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 | |
signature | |
""" | |
if not supported_signature_types: | |
supported_signature_types = {SIGNATURE_TYPE_BINARY} | |
if not supported_hash_algorithms: | |
supported_hash_algorithms = {SHA256} | |
_, header_len, _, packet_len = gpg_util.parse_packet_header( | |
data, PACKET_TYPE_SIGNATURE | |
) | |
data = bytearray(data[header_len:packet_len]) | |
ptr = 0 | |
# we get the version number, which we also expect to be v4, or we bail | |
# FIXME: support v3 type signatures (which I haven't seen in the wild) | |
version_number = data[ptr] | |
ptr += 1 | |
if version_number not in SUPPORTED_SIGNATURE_PACKET_VERSIONS: | |
raise ValueError( | |
"Signature version '{}' not supported, must be one of " | |
"{}.".format(version_number, SUPPORTED_SIGNATURE_PACKET_VERSIONS) | |
) | |
# Per default we only parse "signatures of a binary document". Other types | |
# may be allowed by passing type constants via `supported_signature_types`. | |
# Types include revocation signatures, key binding signatures, persona | |
# certifications, etc. (see RFC 4880 section 5.2.1.). | |
signature_type = data[ptr] | |
ptr += 1 | |
if signature_type not in supported_signature_types: | |
raise ValueError( | |
"Signature type '{}' not supported, must be one of {} " | |
"(see RFC4880 5.2.1. Signature Types).".format( | |
signature_type, supported_signature_types | |
) | |
) | |
signature_algorithm = data[ptr] | |
ptr += 1 | |
if signature_algorithm not in SUPPORTED_SIGNATURE_ALGORITHMS: | |
raise ValueError( | |
"Signature algorithm '{}' not " | |
"supported, please verify that your gpg configuration is creating " | |
"either DSA, RSA, or EdDSA signatures (see RFC4880 9.1. Public-Key " | |
"Algorithms).".format(signature_algorithm) | |
) | |
key_type = SUPPORTED_SIGNATURE_ALGORITHMS[signature_algorithm]["type"] | |
handler = SIGNATURE_HANDLERS[key_type] | |
hash_algorithm = data[ptr] | |
ptr += 1 | |
if hash_algorithm not in supported_hash_algorithms: | |
raise ValueError( | |
"Hash algorithm '{}' not supported, must be one of {}" | |
" (see RFC4880 9.4. Hash Algorithms).".format( | |
hash_algorithm, supported_hash_algorithms | |
) | |
) | |
# Obtain the hashed octets | |
hashed_octet_count = struct.unpack(">H", data[ptr : ptr + 2])[0] | |
ptr += 2 | |
hashed_subpackets = data[ptr : ptr + hashed_octet_count] | |
hashed_subpacket_info = gpg_util.parse_subpackets(hashed_subpackets) | |
# Check whether we were actually able to read this much hashed octets | |
if len(hashed_subpackets) != hashed_octet_count: # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted." | |
"It is missing hashed octets!" | |
) | |
ptr += hashed_octet_count | |
other_headers_ptr = ptr | |
unhashed_octet_count = struct.unpack(">H", data[ptr : ptr + 2])[0] | |
ptr += 2 | |
unhashed_subpackets = data[ptr : ptr + unhashed_octet_count] | |
unhashed_subpacket_info = gpg_util.parse_subpackets(unhashed_subpackets) | |
ptr += unhashed_octet_count | |
# Use the info dict to return further signature information that may be | |
# needed for intermediate processing, but does not have to be on the eventual | |
# signature datastructure | |
info = { | |
"signature_type": signature_type, | |
"hash_algorithm": hash_algorithm, | |
"creation_time": None, | |
"subpackets": {}, | |
} | |
keyid = "" | |
short_keyid = "" | |
# Parse "Issuer" (short keyid) and "Issuer Fingerprint" (full keyid) type | |
# subpackets | |
# Strategy: Loop over all unhashed and hashed subpackets (in that order!) and | |
# store only the last of a type. Due to the order in the loop, hashed | |
# subpackets are prioritized over unhashed subpackets (see NOTEs below). | |
# NOTE: A subpacket may be found either in the hashed or unhashed subpacket | |
# sections of a signature. If a subpacket is not hashed, then the information | |
# in it cannot be considered definitive because it is not part of the | |
# signature proper. (see RFC4880 5.2.3.2.) | |
# NOTE: Signatures may contain conflicting information in subpackets. In most | |
# cases, an implementation SHOULD use the last subpacket, but MAY use any | |
# conflict resolution scheme that makes more sense. (see RFC4880 5.2.4.1.) | |
for idx, subpacket_tuple in enumerate( | |
unhashed_subpacket_info + hashed_subpacket_info | |
): | |
# The idx indicates if the info is from the unhashed (first) or | |
# hashed (second) of the above concatenated lists | |
is_hashed = idx >= len(unhashed_subpacket_info) | |
subpacket_type, subpacket_data = subpacket_tuple | |
# Warn if expiration subpacket is not hashed | |
if subpacket_type == KEY_EXPIRATION_SUBPACKET: | |
if not is_hashed: | |
log.warning( | |
"Expiration subpacket not hashed, gpg client possibly " | |
"exporting a weakly configured key." | |
) | |
# Full keyids are only available in newer signatures | |
# (see RFC4880 and rfc4880bis-06 5.2.3.1.) | |
if subpacket_type == FULL_KEYID_SUBPACKET: # pragma: no cover | |
# Exclude from coverage for consistent results across test envs | |
# NOTE: The first byte of the subpacket payload is a version number | |
# (see rfc4880bis-06 5.2.3.28.) | |
keyid = binascii.hexlify(subpacket_data[1:]).decode("ascii") | |
# We also return the short keyid, because the full might not be available | |
if subpacket_type == PARTIAL_KEYID_SUBPACKET: | |
short_keyid = binascii.hexlify(subpacket_data).decode("ascii") | |
if subpacket_type == SIG_CREATION_SUBPACKET: | |
info["creation_time"] = struct.unpack(">I", subpacket_data)[0] | |
info["subpackets"][subpacket_type] = subpacket_data | |
# Fail if there is no keyid at all (this should not happen) | |
if not (keyid or short_keyid): # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted. It does " | |
"not have an 'Issuer' or 'Issuer Fingerprint' subpacket (see RFC4880 " | |
"and rfc4880bis-06 5.2.3.1. Signature Subpacket Specification)." | |
) | |
# Fail if keyid and short keyid are specified but don't match | |
if keyid and not keyid.endswith(short_keyid): # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted. The key ID " | |
"'{}' of the 'Issuer' subpacket must match the lower 64 bits of the " | |
"fingerprint '{}' of the 'Issuer Fingerprint' subpacket (see RFC4880 " | |
"and rfc4880bis-06 5.2.3.28. Issuer Fingerprint).".format( | |
short_keyid, keyid | |
) | |
) | |
if not info["creation_time"]: # pragma: no cover | |
raise ValueError( | |
"This signature packet seems to be corrupted. It does " | |
"not have a 'Signature Creation Time' subpacket (see RFC4880 5.2.3.4 " | |
"Signature Creation Time)." | |
) | |
# Uncomment this variable to obtain the left-hash-bits information (used for | |
# early rejection) | |
# left_hash_bits = struct.unpack(">H", data[ptr:ptr+2])[0] | |
ptr += 2 | |
# Finally, fetch the actual signature (as opposed to signature metadata). | |
signature = handler.get_signature_params(data[ptr:]) | |
signature_data = { | |
"keyid": "{}".format(keyid), | |
"other_headers": binascii.hexlify(data[:other_headers_ptr]).decode( | |
"ascii" | |
), | |
"signature": binascii.hexlify(signature).decode("ascii"), | |
} | |
if short_keyid: # pragma: no branch | |
signature_data["short_keyid"] = short_keyid | |
if include_info: | |
signature_data["info"] = info | |
return signature_data |
PLR0913: too-many-arguments
securesystemslib/securesystemslib/signer/_sigstore_signer.py
Lines 37 to 44 in db0a9a5
def __init__( # noqa: PLR0913 | |
self, | |
keyid: str, | |
keytype: str, | |
scheme: str, | |
keyval: Dict[str, Any], | |
unrecognized_fields: Optional[Dict[str, Any]] = None, | |
): |
E402: module-import-not-at-top-of-file
https://github.com/secure-systems-lab/securesystemslib/blob/db0a9a5afe9604f4e614e1979d0559832df64a08/securesystemslib/_gpg/dsa.py#L30C15-L33
securesystemslib/securesystemslib/_gpg/rsa.py
Lines 29 to 32 in db0a9a5
# ruff: noqa: E402 | |
from securesystemslib import exceptions | |
from securesystemslib._gpg import util as gpg_util | |
from securesystemslib._gpg.exceptions import PacketParsingError |
securesystemslib/securesystemslib/_gpg/util.py
Lines 33 to 36 in db0a9a5
# ruff: noqa: E402 | |
from securesystemslib import exceptions | |
from securesystemslib._gpg import constants | |
from securesystemslib._gpg.exceptions import PacketParsingError |