def test_verify_signatures(image_config: ImageConfig): """Test signature verification for signed and unsigned configurations.""" # Unsigned configurations should explicitly raise an exception. with pytest.raises(Exception) as e: image_config.verify_signatures() assert str(e.value) == "Image does not contain any signatures!" # Sign a previously unsigned configuration, so that only the new signature type is present. # Note: It is not trivial to embed "known" GPG / PKI signature types, as assumptions about the # test environment are difficult to make. image_config.sign(FakeSigner()) # An exception should be raised if the provider for a signature type is not known with pytest.raises(Exception) as e: image_config.verify_signatures() assert str(e.value) == "Unsupported signature type!" # Replace the class method for resolving signature providers ... original_method = Signer.for_signature Signer.for_signature = _signer_for_signature # The Signer's verify() method should be invoked. assert image_config.verify_signatures()["results"] == [{ "type": "fake", "valid": True }] # Restore the original class method Signer.for_signature = original_method
def test_acceptance_sign_unsign_symmetry(image_config: ImageConfig, image_config_signed: ImageConfig): """Tests that sign and unsign are (mostly) symmetric operations.""" config_digest = image_config.get_config_digest() # 1. Sign signer = FakeSigner() assert image_config.sign(signer) == signer.signature_value assert image_config_signed.sign(signer) == signer.signature_value # Previously unsigned configurations should now contain the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config.get_config() # Previously signed configurations should now contain the original signature(s) and the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config_signed.get_config() assert b"BEGIN PGP SIGNATURE" in image_config_signed.get_config() # 2. Unsign image_config.unsign() image_config_signed.unsign() # Configurations where we added the first signature should be reverted. assert b"BEGIN FAKE SIGNATURE" not in image_config.get_config() # Configurations where we appended a signature should now contain no signature(s). assert b"BEGIN FAKE SIGNATURE" not in image_config_signed.get_config() assert b"BEGIN PGP SIGNATURE" not in image_config_signed.get_config() assert image_config.get_config_digest() == config_digest
def test_sign_resign( image_config: ImageConfig, image_config_signed: ImageConfig, config_digest_canonical: str, config_digest_signed_canonical: str, signature: str, ): """Test configuration resigning for signed and unsigned configurations.""" signer = FakeSigner() assert image_config.sign(signer, SignatureTypes.RESIGN) == signer.signature_value assert (image_config_signed.sign( signer, SignatureTypes.RESIGN) == signer.signature_value) # Previously unsigned configurations should now contain the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config.get_config() signatures = image_config.get_signature_list() assert len(signatures) == 1 assert signatures[0]["digest"] == config_digest_canonical assert signatures[0]["signature"] == signer.signature_value # Previously signed configurations should now contain (only) the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config_signed.get_config() assert b"BEGIN PGP SIGNATURE" not in image_config_signed.get_config() signatures_signed = image_config_signed.get_signature_list() assert len(signatures_signed) == 1 assert signatures[0]["digest"] == config_digest_canonical assert signatures[0]["signature"] == signer.signature_value
def test_sign_endorse( image_config: ImageConfig, image_config_signed: ImageConfig, config_digest_canonical: str, config_digest_signed_canonical: str, signature: str, ): """Test configuration endorsement for signed and unsigned configurations.""" signer = FakeSigner() assert image_config.sign(signer, SignatureTypes.ENDORSE) == signer.signature_value assert (image_config_signed.sign( signer, SignatureTypes.ENDORSE) == signer.signature_value) # Previously unsigned configurations should now contain the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config.get_config() signatures = image_config.get_signature_list() assert len(signatures) == 1 assert signatures[0]["digest"] == config_digest_canonical assert signatures[0]["signature"] == signer.signature_value # Previously signed configurations should now contain the original signature(s) and the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config_signed.get_config() assert b"BEGIN PGP SIGNATURE" in image_config_signed.get_config() signatures_signed = image_config_signed.get_signature_list() assert len(signatures_signed) == 2 assert signatures_signed[0]["digest"] == config_digest_canonical assert signatures_signed[0]["signature"] == signature assert signatures_signed[1]["digest"] == config_digest_signed_canonical assert signatures_signed[1]["signature"] == signer.signature_value
def append_new_image_config(config: ImageConfig, endorse: bool = False, iteration=i): signer = FakeSigner("<<< {0} {1}: {2} >>>".format( iteration, "Endorsing" if endorse else "Signing", config.get_config_digest_canonical(), )) config.sign(signer, endorse) stack.append(config)
def test_sign(image_config: ImageConfig, image_config_signed: ImageConfig): """Test configuration signing for signed and unsigned configurations.""" signer = FakeSigner() assert image_config.sign(signer) == signer.signature_value assert image_config_signed.sign(signer) == signer.signature_value # Previously unsigned configurations should now contain the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config.get_config() # Previously signed configurations should now contain the original signature(s) and the new signature. assert b"BEGIN FAKE SIGNATURE" in image_config_signed.get_config() assert b"BEGIN PGP SIGNATURE" in image_config_signed.get_config()
def append_new_image_config( config: ImageConfig, signature_type: SignatureTypes = SignatureTypes.SIGN, iteration=i, ): signer = FakeSigner("<<< {0} {1}: {2} >>>".format( iteration, "Endorsing" if signature_type == SignatureTypes.ENDORSE else "Signing", config.get_config_digest_canonical(), )) config.sign(signer, signature_type) stack.append(config)
def test_verify_signatures_manipulated_signatures(image_config: ImageConfig): """Test that signature verification detects manipulated signatures.""" # Add a single signature ... signer = FakeSigner() assert image_config.sign(signer) == signer.signature_value # Replace the class method for resolving signature providers ... original_method = Signer.for_signature Signer.for_signature = _signer_for_signature # Sanity check assert image_config.verify_signatures()["results"][0]["valid"] is True # Modify the digest value of the (first) signature ... signatures = image_config.get_signature_list() temp = copy.deepcopy(signatures) temp[0]["digest"] = "tampertampertamper" image_config.set_signature_list(temp) # An exception should be raised if digest value from the signature does not match the canonical digest of the image # configuration (without any signatures). with pytest.raises(Exception) as exception: image_config.verify_signatures() assert str( exception.value).startswith("Image config canonical digest mismatch:") # Restore the unmodified signature and endorse ... image_config.set_signature_list(signatures) assert image_config.sign(signer, SignatureTypes.ENDORSE) == signer.signature_value # Sanity check assert image_config.verify_signatures()["results"][0]["valid"] is True # Modify the digest value of the second signature ... signatures = image_config.get_signature_list() temp = copy.deepcopy(signatures) temp[1]["digest"] = "tampertampertamper" image_config.set_signature_list(temp) # An exception should be raised if digest value from the signature does not match the canonical digest of the image # configuration (including the first signature). with pytest.raises(Exception) as exception: image_config.verify_signatures() assert str( exception.value).startswith("Image config canonical digest mismatch:") # Restore the original class method Signer.for_signature = original_method
def test_minimal(): """Test minimal image configuration (for non-conformant labels)k.""" # Note: At a minimum, [Cc]onfig key must exist with non-null value image_config = ImageConfig(b'{"Config":{}}') config_digest_canonical = image_config.get_config_digest_canonical() signer = FakeSigner() assert image_config.sign(signer) == signer.signature_value # A signature should always be able to be added ... assert b"BEGIN FAKE SIGNATURE" in image_config.get_config() signatures = image_config.get_signature_list() assert len(signatures) == 1 assert signatures[0]["digest"] == config_digest_canonical assert signatures[0]["signature"] == signer.signature_value