-
Notifications
You must be signed in to change notification settings - Fork 54
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 |