async def test_sign_resign( image_config: ImageConfig, image_config_signed: ImageConfig, config_digest_canonical: str, ): """Test configuration resigning for signed and unsigned configurations.""" signer = FakeSigner() assert ( await image_config.sign(signer, SignatureTypes.RESIGN) == signer.signature_value ) assert ( await 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_bytes() 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_bytes() assert b"BEGIN PGP SIGNATURE" not in image_config_signed.get_bytes() 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
async def test_sign_resign( config_digest_canonical: str, gnupg_keypair: GnuPGKeypair, image_config: ImageConfig, image_config_signed: ImageConfig, ): """Test configuration resigning for signed and unsigned configurations.""" signer = GPGSigner( keyid=gnupg_keypair.keyid, passphrase=gnupg_keypair.passphrase, homedir=gnupg_keypair.gnupg_home, ) sig = await image_config.sign(signer, SignatureTypes.RESIGN) assert "PGP SIGNATURE" in sig sig_signed = await image_config_signed.sign(signer, SignatureTypes.RESIGN) assert "PGP SIGNATURE" in sig_signed # Previously unsigned configurations should now contain the new signature. signatures = image_config.get_signature_list() assert len(signatures) == 1 assert signatures[0].digest == config_digest_canonical assert signatures[0].signature == sig # Previously signed configurations should now contain (only) the new signature. assert image_config_signed.get_bytes().count(b"BEGIN PGP SIGNATURE") == 1 signatures_signed = image_config_signed.get_signature_list() assert len(signatures_signed) == 1 assert signatures[0].digest == config_digest_canonical assert signatures[0].signature == sig_signed
async 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 ( await image_config.sign(signer, SignatureTypes.ENDORSE) == signer.signature_value ) assert ( await 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_bytes() 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_bytes() assert b"BEGIN PGP SIGNATURE" in image_config_signed.get_bytes() 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
async def test_sign_endorse( config_digest_canonical: str, config_digest_signed_canonical: str, gnupg_keypair: GnuPGKeypair, image_config: ImageConfig, image_config_signed: ImageConfig, signature: str, ): """Test configuration endorsement for signed and unsigned configurations.""" signer = GPGSigner( keyid=gnupg_keypair.keyid, passphrase=gnupg_keypair.passphrase, homedir=gnupg_keypair.gnupg_home, ) sig = await image_config.sign(signer, SignatureTypes.ENDORSE) assert "PGP SIGNATURE" in sig sig_signed = await image_config_signed.sign(signer, SignatureTypes.ENDORSE) assert "PGP SIGNATURE" in sig_signed # Previously unsigned configurations should now contain the new signature. signatures = image_config.get_signature_list() assert len(signatures) == 1 assert signatures[0].digest == config_digest_canonical assert signatures[0].signature == sig # Previously signed configurations should now contain the original signature(s) and the new signature. assert image_config_signed.get_bytes().count(b"BEGIN PGP SIGNATURE") == 2 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 == sig_signed
def test_clear_signature_list( image_config: ImageConfig, image_config_signed: ImageConfig ): """Test signature data parsing for signed and unsigned configurations.""" image_config_signed.clear_signature_list() assert not image_config_signed.get_signature_list() image_config.clear_signature_list() signatures_unsigned = image_config.get_signature_list() assert not signatures_unsigned
async def test_verify_signatures_manipulated_signatures( gnupg_keypair: GnuPGKeypair, image_config: ImageConfig ): """Test that signature verification detects manipulated signatures.""" signer = GPGSigner( keyid=gnupg_keypair.keyid, passphrase=gnupg_keypair.passphrase, homedir=gnupg_keypair.gnupg_home, ) # Add a single signature ... await image_config.sign(signer) response = await image_config.verify_signatures( signer_kwargs={GPGSigner.__name__: {"homedir": gnupg_keypair.gnupg_home}} ) assert response.results[0].valid # Modify the digest value of the (first) signature ... signatures = image_config.get_signature_list() temp = deepcopy(signatures) temp[0] = ImageConfigSignatureEntry( digest=FormattedSHA256.calculate(b"tampertampertamper"), signature=temp[0].signature, ) 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(DigestMismatchError) as exception: await 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) await image_config.sign(signer, SignatureTypes.ENDORSE) response = await image_config.verify_signatures( signer_kwargs={GPGSigner.__name__: {"homedir": gnupg_keypair.gnupg_home}} ) assert response.results[0].valid # Modify the digest value of the second signature ... signatures = image_config.get_signature_list() temp = deepcopy(signatures) temp[1] = ImageConfigSignatureEntry( digest=FormattedSHA256.calculate(b"tampertampertamper"), signature=temp[1].signature, ) 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(DigestMismatchError) as exception: await image_config.verify_signatures() assert str(exception.value).startswith("Image config canonical digest mismatch:")
async def test_verify_signatures_manipulated_signatures(image_config: ImageConfig): """Test that signature verification detects manipulated signatures.""" # Add a single signature ... signer = FakeSigner() assert await 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 response = await image_config.verify_signatures() assert response["results"][0]["valid"] is True # Modify the digest value of the (first) signature ... signatures = image_config.get_signature_list() temp = 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(DigestMismatchError) as exception: await 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 ( await image_config.sign(signer, SignatureTypes.ENDORSE) == signer.signature_value ) # Sanity check response = await image_config.verify_signatures() assert response["results"][0]["valid"] is True # Modify the digest value of the second signature ... signatures = image_config.get_signature_list() temp = 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(DigestMismatchError) as exception: await 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_get_signature_list( image_config: ImageConfig, image_config_signed: ImageConfig, config_digest_canonical: str, signature: str, ): """Test signature data parsing for signed and unsigned configurations.""" signatures_signed = image_config_signed.get_signature_list() assert len(signatures_signed) == 1 assert signatures_signed[0]["digest"] == config_digest_canonical assert signatures_signed[0]["signature"] == signature signatures_unsigned = image_config.get_signature_list() assert not signatures_unsigned
async 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_digest_canonical() signer = FakeSigner() assert await 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_bytes() signatures = image_config.get_signature_list() assert len(signatures) == 1 assert signatures[0]["digest"] == config_digest_canonical assert signatures[0]["signature"] == signer.signature_value
async def test_minimal(gnupg_keypair: GnuPGKeypair): """Test minimal image configuration (for non-conformant labels)k.""" signer = GPGSigner( keyid=gnupg_keypair.keyid, passphrase=gnupg_keypair.passphrase, homedir=gnupg_keypair.gnupg_home, ) # Note: At a minimum, [Cc]onfig key must exist with non-null value image_config = ImageConfig(b'{"Config":{}}') config_digest_canonical = image_config.get_digest_canonical() signature = await image_config.sign(signer) assert "PGP SIGNATURE" in signature # A signature should always be able to be added ... assert b"BEGIN PGP SIGNATURE" in image_config.get_bytes() signatures = image_config.get_signature_list() assert len(signatures) == 1 assert signatures[0].digest == config_digest_canonical assert signatures[0].signature == signature