Skip to content

Commit 7b37bc4

Browse files
authored
fuzzing: allow fuzzers to choose the serialization method (#556)
Signed-off-by: Adam Korczynski <[email protected]>
1 parent a95aada commit 7b37bc4

7 files changed

+66
-14
lines changed

tests/fuzzing/fuzz_sign_then_mutate_verify_with_valid_key.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import atheris # type: ignore
2323
from cryptography.hazmat.primitives import serialization
2424
from cryptography.hazmat.primitives.asymmetric import ec
25+
from utils import _build_hashing_config_from_fdp
2526
from utils import any_files
2627
from utils import create_fuzz_files
2728
from utils import safe_write
@@ -98,8 +99,11 @@ def TestOneInput(data: bytes) -> None:
9899

99100
key_spec = _pick_key_spec(fdp)
100101

102+
hcfg = _build_hashing_config_from_fdp(fdp)
103+
101104
# Sign the directory root with a valid private key.
102105
scfg = model_signing.signing.Config()
106+
scfg.set_hashing_config(hcfg)
103107
signer = scfg.use_elliptic_key_signer(private_key=key_spec["priv"])
104108
_ = signer.sign(model_path, sig_path)
105109

@@ -134,6 +138,7 @@ def TestOneInput(data: bytes) -> None:
134138

135139
# Verification must fail with ValueError because the tree changed.
136140
vcfg = model_signing.verifying.Config()
141+
vcfg.set_hashing_config(hcfg)
137142
verifier = vcfg.use_elliptic_key_verifier(public_key=key_spec["pub"])
138143
try:
139144
verifier.verify(model_path, sig_path)

tests/fuzzing/fuzz_sign_verify_with_valid_key.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import atheris
2424
from cryptography.hazmat.primitives import serialization
2525
from cryptography.hazmat.primitives.asymmetric import ec
26+
from utils import _build_hashing_config_from_fdp
2627
from utils import any_files
2728
from utils import create_fuzz_files
2829

@@ -98,11 +99,15 @@ def TestOneInput(data: bytes) -> None:
9899

99100
key_spec = _pick_key_spec(fdp)
100101

102+
hcfg = _build_hashing_config_from_fdp(fdp)
103+
101104
scfg = model_signing.signing.Config()
105+
scfg.set_hashing_config(hcfg)
102106
signer = scfg.use_elliptic_key_signer(private_key=key_spec["priv"])
103107
_ = signer.sign(model_path, sig_path)
104108

105109
vcfg = model_signing.verifying.Config()
110+
vcfg.set_hashing_config(hcfg)
106111
verifier = vcfg.use_elliptic_key_verifier(public_key=key_spec["pub"])
107112
verifier.verify(model_path, sig_path)
108113

tests/fuzzing/fuzz_sign_with_invalid_key.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
# type: ignore
2121
import atheris
2222
from cryptography.hazmat.primitives import serialization
23+
from utils import _build_hashing_config_from_fdp
2324
from utils import any_files
2425
from utils import create_fuzz_files
2526

@@ -63,7 +64,10 @@ def TestOneInput(data: bytes) -> None:
6364
model_path = str(root)
6465
sig_path = os.path.join(sigdir, "model.sig")
6566

67+
hcfg = _build_hashing_config_from_fdp(fdp)
68+
6669
scfg = model_signing.signing.Config()
70+
scfg.set_hashing_config(hcfg)
6771
signer = scfg.use_elliptic_key_signer(private_key=key_path)
6872
_ = signer.sign(model_path, sig_path)
6973

tests/fuzzing/fuzz_sign_with_valid_key_verify_with_invalid_key.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import atheris
2424
from cryptography.hazmat.primitives import serialization
2525
from cryptography.hazmat.primitives.asymmetric import ec
26+
from utils import _build_hashing_config_from_fdp
2627
from utils import any_files
2728
from utils import create_fuzz_files
2829

@@ -90,8 +91,11 @@ def TestOneInput(data: bytes) -> None:
9091
model_path = str(root)
9192
sig_path = os.path.join(sigdir, "model.sig")
9293

94+
hcfg = _build_hashing_config_from_fdp(fdp)
95+
9396
# Sign using the valid private key created at module import time.
9497
scfg = model_signing.signing.Config()
98+
scfg.set_hashing_config(hcfg)
9599
signer = scfg.use_elliptic_key_signer(private_key=_PRIV_PATH)
96100
_ = signer.sign(model_path, sig_path)
97101

@@ -102,6 +106,7 @@ def TestOneInput(data: bytes) -> None:
102106

103107
# Verify with the fuzzed public key.
104108
vcfg = model_signing.verifying.Config()
109+
vcfg.set_hashing_config(hcfg)
105110
verifier = vcfg.use_elliptic_key_verifier(public_key=pubkey_path)
106111
verifier.verify(model_path, sig_path)
107112

tests/fuzzing/fuzz_simple_sigstore.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
# type: ignore
2222
import atheris
2323
from sigstore.models import TrustedRoot
24+
from utils import _build_hashing_config_from_fdp
2425
from utils import any_files
2526
from utils import create_fuzz_files
2627

@@ -131,7 +132,10 @@ def TestOneInput(data: bytes) -> None:
131132
fdp.ConsumeBytes(64).decode("utf-8", errors="ignore") or "token"
132133
)
133134

135+
hcfg = _build_hashing_config_from_fdp(fdp)
136+
134137
sc = signing.Config()
138+
sc.set_hashing_config(hcfg)
135139
sc.use_sigstore_signer(
136140
use_staging=True, identity_token=sigstore_oidc_beacon_token
137141
)
@@ -142,6 +146,7 @@ def TestOneInput(data: bytes) -> None:
142146

143147
# 7) Verify
144148
vc = verifying.Config()
149+
vc.set_hashing_config(hcfg)
145150
vc.use_sigstore_verifier(
146151
identity=expected_identity,
147152
oidc_issuer=expected_oidc_issuer,

tests/fuzzing/fuzz_with_cert_chain.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,23 @@ def key_to_pem(priv: rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey) -> bytes:
278278
)
279279

280280

281+
def _build_hashing_config_from_fdp(
282+
fdp: atheris.FuzzedDataProvider,
283+
extra_ignores: list[Path],
284+
signature_path: Path,
285+
) -> hashing.Config:
286+
alg = ["sha256", "blake2", "blake3"][fdp.ConsumeIntInRange(0, 2)]
287+
hcfg = hashing.Config().set_ignored_paths(
288+
paths=[*list(extra_ignores), signature_path],
289+
ignore_git_paths=fdp.ConsumeBool(),
290+
)
291+
if fdp.ConsumeBool():
292+
hcfg.use_file_serialization(hashing_algorithm=alg)
293+
else:
294+
hcfg.use_shard_serialization(hashing_algorithm=alg)
295+
return hcfg
296+
297+
281298
def TestOneInput(data: bytes):
282299
fdp = atheris.FuzzedDataProvider(data)
283300

@@ -331,31 +348,23 @@ def TestOneInput(data: bytes):
331348
fname = f"signature-{_rand_utf8(fdp, 3, 12).replace('/', '_')}.sig"
332349
signature_path = model_path_p / fname
333350

334-
# Ignores
335-
ignore_git = fdp.ConsumeBool()
351+
# Ignores (collected for hashing config)
336352
extra_ignores: list[Path] = []
337353

354+
# Build hashing config (serialization + algorithm + ignores)
355+
hcfg = _build_hashing_config_from_fdp(fdp, extra_ignores, signature_path)
356+
338357
# 4) Sign and 5) Verify
339358
try:
340359
signing.Config().use_certificate_signer(
341360
private_key=leaf_key_path,
342361
signing_certificate=leaf_cert_path,
343362
certificate_chain=chain_paths,
344-
).set_hashing_config(
345-
hashing.Config().set_ignored_paths(
346-
paths=[*list(extra_ignores), signature_path],
347-
ignore_git_paths=ignore_git,
348-
)
349-
).sign(model_path_p, signature_path)
363+
).set_hashing_config(hcfg).sign(model_path_p, signature_path)
350364

351365
verifying.Config().use_certificate_verifier(
352366
certificate_chain=chain_paths, log_fingerprints=False
353-
).set_hashing_config(
354-
hashing.Config().set_ignored_paths(
355-
paths=[*list(extra_ignores), signature_path],
356-
ignore_git_paths=ignore_git,
357-
)
358-
).verify(model_path_p, signature_path)
367+
).set_hashing_config(hcfg).verify(model_path_p, signature_path)
359368

360369
finally:
361370
# Always clean up temp dirs

tests/fuzzing/utils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
# type: ignore
2020
import atheris
2121

22+
import model_signing
23+
2224

2325
_SAFE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"
2426

@@ -126,3 +128,20 @@ def create_fuzz_files(root: Path, fdp: atheris.FuzzedDataProvider) -> int:
126128
def any_files(root: Path) -> bool:
127129
"""True if there is at least one regular file under root."""
128130
return any(p.is_file() for p in root.rglob("*"))
131+
132+
133+
def _build_hashing_config_from_fdp(
134+
fdp: atheris.FuzzedDataProvider,
135+
) -> "model_signing.hashing.Config":
136+
"""Randomize serialization strategy and hash algorithm."""
137+
alg = ["sha256", "blake2", "blake3"][fdp.ConsumeIntInRange(0, 2)]
138+
139+
hcfg = model_signing.hashing.Config()
140+
# Choose serialization mode: file vs shard
141+
if fdp.ConsumeBool():
142+
# File-based serialization.
143+
hcfg.use_file_serialization(hashing_algorithm=alg)
144+
else:
145+
# Sharded file serialization
146+
hcfg.use_shard_serialization(hashing_algorithm=alg)
147+
return hcfg

0 commit comments

Comments
 (0)