Skip to content

Commit 9f0d8d7

Browse files
refactor entry validation
Signed-off-by: Ramon Petgrave <[email protected]>
1 parent 08c89bb commit 9f0d8d7

File tree

1 file changed

+141
-112
lines changed

1 file changed

+141
-112
lines changed

sigstore/verify/verifier.py

Lines changed: 141 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -440,73 +440,9 @@ def verify_dsse(
440440
entry._kind_version.kind == "dsse"
441441
and entry._kind_version.version == "0.0.2"
442442
):
443-
try:
444-
v2_body = v2.Entry().from_json(base64.b64decode(entry.body))
445-
except ValidationError as exc:
446-
raise VerificationError(f"invalid DSSE log entry: {exc}")
447-
448-
if v2_body.spec.dsse_v002 is None:
449-
raise VerificationError(
450-
"invalid DSSE log entry: missing dsse_v002 field"
451-
)
452-
453-
if (
454-
v2_body.spec.dsse_v002.payload_hash.algorithm
455-
!= v1.HashAlgorithm.SHA2_256
456-
):
457-
raise VerificationError("expected SHA256 hash in DSSE entry")
458-
459-
digest = sha256_digest(envelope._inner.payload).digest
460-
if v2_body.spec.dsse_v002.payload_hash.digest != digest:
461-
raise VerificationError("DSSE entry payload hash does not match bundle")
462-
463-
v2_signatures = [
464-
v2.Signature(
465-
content=signature.sig,
466-
verifier=v2.Verifier(
467-
x509_certificate=v1.X509Certificate(
468-
bundle.signing_certificate.public_bytes(
469-
encoding=serialization.Encoding.DER
470-
)
471-
),
472-
key_details=self._get_key_details(bundle.signing_certificate),
473-
),
474-
)
475-
for signature in envelope._inner.signatures
476-
]
477-
if v2_signatures != v2_body.spec.dsse_v002.signatures:
478-
raise VerificationError("log entry signatures do not match bundle")
443+
validate_dsse_v002_entry_body(bundle)
479444
else:
480-
try:
481-
entry_body = rekor_types.Dsse.model_validate_json(
482-
base64.b64decode(entry.body)
483-
)
484-
except ValidationError as exc:
485-
raise VerificationError(f"invalid DSSE log entry: {exc}")
486-
487-
payload_hash = sha256_digest(envelope._inner.payload).digest.hex()
488-
if (
489-
entry_body.spec.root.payload_hash.algorithm # type: ignore[union-attr]
490-
!= rekor_types.dsse.Algorithm.SHA256
491-
):
492-
raise VerificationError(
493-
"expected SHA256 payload hash in DSSE log entry"
494-
)
495-
if payload_hash != entry_body.spec.root.payload_hash.value: # type: ignore[union-attr]
496-
raise VerificationError("log entry payload hash does not match bundle")
497-
498-
# NOTE: Like `dsse._verify`: multiple signatures would be frivolous here,
499-
# but we handle them just in case the signer has somehow produced multiple
500-
# signatures for their envelope with the same signing key.
501-
signatures = [
502-
rekor_types.dsse.Signature(
503-
signature=base64.b64encode(signature.sig).decode(),
504-
verifier=base64_encode_pem_cert(bundle.signing_certificate),
505-
)
506-
for signature in envelope._inner.signatures
507-
]
508-
if signatures != entry_body.spec.root.signatures:
509-
raise VerificationError("log entry signatures do not match bundle")
445+
validate_dsse_v001_entry_body(bundle)
510446

511447
return (envelope._inner.payload_type, envelope._inner.payload)
512448

@@ -551,58 +487,151 @@ def verify_artifact(
551487
# (8): verify the consistency of the log entry's body against
552488
# the other bundle materials (and input being verified).
553489
entry = bundle.log_entry
554-
555490
if (
556491
entry._kind_version.kind == "hashedrekord"
557492
and entry._kind_version.version == "0.0.2"
558493
):
559-
if bundle._inner.message_signature is None:
560-
raise VerificationError(
561-
"invalid hashedrekord log entry: missing message signature"
562-
)
494+
validate_hashedrekord_v002_entry_body(bundle)
495+
else:
496+
validate_hashedrekord_v001_entry_body(bundle, hashed_input)
563497

564-
v2_expected_body = v2.Entry(
565-
kind=entry._kind_version.kind,
566-
api_version=entry._kind_version.version,
567-
spec=v2.Spec(
568-
hashed_rekord_v002=v2.HashedRekordLogEntryV002(
569-
data=v1.HashOutput(
570-
algorithm=bundle._inner.message_signature.message_digest.algorithm,
571-
digest=bundle._inner.message_signature.message_digest.digest,
572-
),
573-
signature=v2.Signature(
574-
content=bundle._inner.message_signature.signature,
575-
verifier=v2.Verifier(
576-
x509_certificate=v1.X509Certificate(
577-
bundle.signing_certificate.public_bytes(
578-
encoding=serialization.Encoding.DER
579-
)
580-
),
581-
key_details=self._get_key_details(
582-
bundle.signing_certificate
583-
),
584-
),
585-
),
498+
499+
def validate_dsse_v001_entry_body(bundle: Bundle) -> None:
500+
"""
501+
Valideate the Entry body for dsse v001.
502+
"""
503+
entry = bundle.log_entry
504+
envelope = bundle._dsse_envelope
505+
if envelope is None:
506+
raise VerificationError(
507+
"cannot perform DSSE verification on a bundle without a DSSE envelope"
508+
)
509+
try:
510+
entry_body = rekor_types.Dsse.model_validate_json(base64.b64decode(entry.body))
511+
except ValidationError as exc:
512+
raise VerificationError(f"invalid DSSE log entry: {exc}")
513+
514+
payload_hash = sha256_digest(envelope._inner.payload).digest.hex()
515+
if (
516+
entry_body.spec.root.payload_hash.algorithm # type: ignore[union-attr]
517+
!= rekor_types.dsse.Algorithm.SHA256
518+
):
519+
raise VerificationError("expected SHA256 payload hash in DSSE log entry")
520+
if payload_hash != entry_body.spec.root.payload_hash.value: # type: ignore[union-attr]
521+
raise VerificationError("log entry payload hash does not match bundle")
522+
523+
# NOTE: Like `dsse._verify`: multiple signatures would be frivolous here,
524+
# but we handle them just in case the signer has somehow produced multiple
525+
# signatures for their envelope with the same signing key.
526+
signatures = [
527+
rekor_types.dsse.Signature(
528+
signature=base64.b64encode(signature.sig).decode(),
529+
verifier=base64_encode_pem_cert(bundle.signing_certificate),
530+
)
531+
for signature in envelope._inner.signatures
532+
]
533+
if signatures != entry_body.spec.root.signatures:
534+
raise VerificationError("log entry signatures do not match bundle")
535+
536+
537+
def validate_dsse_v002_entry_body(bundle: Bundle) -> None:
538+
"""
539+
Valideate the Entry body for dsse v002.
540+
"""
541+
entry = bundle.log_entry
542+
envelope = bundle._dsse_envelope
543+
if envelope is None:
544+
raise VerificationError(
545+
"cannot perform DSSE verification on a bundle without a DSSE envelope"
546+
)
547+
try:
548+
v2_body = v2.Entry().from_json(base64.b64decode(entry.body))
549+
except ValidationError as exc:
550+
raise VerificationError(f"invalid DSSE log entry: {exc}")
551+
552+
if v2_body.spec.dsse_v002 is None:
553+
raise VerificationError("invalid DSSE log entry: missing dsse_v002 field")
554+
555+
if v2_body.spec.dsse_v002.payload_hash.algorithm != v1.HashAlgorithm.SHA2_256:
556+
raise VerificationError("expected SHA256 hash in DSSE entry")
557+
558+
digest = sha256_digest(envelope._inner.payload).digest
559+
if v2_body.spec.dsse_v002.payload_hash.digest != digest:
560+
raise VerificationError("DSSE entry payload hash does not match bundle")
561+
562+
v2_signatures = [
563+
v2.Signature(
564+
content=signature.sig,
565+
verifier=v2.Verifier(
566+
x509_certificate=v1.X509Certificate(
567+
bundle.signing_certificate.public_bytes(
568+
encoding=serialization.Encoding.DER
586569
)
587570
),
588-
)
589-
v2_actual_body = v2.Entry().from_json(base64.b64decode(entry.body))
590-
if v2_expected_body != v2_actual_body:
591-
raise VerificationError(
592-
"transparency log entry is inconsistent with other materials"
593-
)
571+
key_details=Verifier._get_key_details(bundle.signing_certificate),
572+
),
573+
)
574+
for signature in envelope._inner.signatures
575+
]
576+
if v2_signatures != v2_body.spec.dsse_v002.signatures:
577+
raise VerificationError("log entry signatures do not match bundle")
594578

595-
else:
596-
expected_body = _hashedrekord_from_parts(
597-
bundle.signing_certificate,
598-
bundle._inner.message_signature.signature, # type: ignore[union-attr]
599-
hashed_input,
600-
)
601-
actual_body = rekor_types.Hashedrekord.model_validate_json(
602-
base64.b64decode(entry.body)
603-
)
604579

605-
if expected_body != actual_body:
606-
raise VerificationError(
607-
"transparency log entry is inconsistent with other materials"
608-
)
580+
def validate_hashedrekord_v001_entry_body(bundle: Bundle, hashed_input: Hashed) -> None:
581+
"""
582+
Valideate the Entry body for hashedrekord v001.
583+
"""
584+
entry = bundle.log_entry
585+
expected_body = _hashedrekord_from_parts(
586+
bundle.signing_certificate,
587+
bundle._inner.message_signature.signature, # type: ignore[union-attr]
588+
hashed_input,
589+
)
590+
actual_body = rekor_types.Hashedrekord.model_validate_json(
591+
base64.b64decode(entry.body)
592+
)
593+
if expected_body != actual_body:
594+
raise VerificationError(
595+
"transparency log entry is inconsistent with other materials"
596+
)
597+
598+
599+
def validate_hashedrekord_v002_entry_body(bundle: Bundle) -> None:
600+
"""
601+
Valideate the Entry body for hashedrekord v002.
602+
"""
603+
entry = bundle.log_entry
604+
if bundle._inner.message_signature is None:
605+
raise VerificationError(
606+
"invalid hashedrekord log entry: missing message signature"
607+
)
608+
v2_expected_body = v2.Entry(
609+
kind=entry._kind_version.kind,
610+
api_version=entry._kind_version.version,
611+
spec=v2.Spec(
612+
hashed_rekord_v002=v2.HashedRekordLogEntryV002(
613+
data=v1.HashOutput(
614+
algorithm=bundle._inner.message_signature.message_digest.algorithm,
615+
digest=bundle._inner.message_signature.message_digest.digest,
616+
),
617+
signature=v2.Signature(
618+
content=bundle._inner.message_signature.signature,
619+
verifier=v2.Verifier(
620+
x509_certificate=v1.X509Certificate(
621+
bundle.signing_certificate.public_bytes(
622+
encoding=serialization.Encoding.DER
623+
)
624+
),
625+
key_details=Verifier._get_key_details(
626+
bundle.signing_certificate
627+
),
628+
),
629+
),
630+
)
631+
),
632+
)
633+
v2_actual_body = v2.Entry().from_json(base64.b64decode(entry.body))
634+
if v2_expected_body != v2_actual_body:
635+
raise VerificationError(
636+
"transparency log entry is inconsistent with other materials"
637+
)

0 commit comments

Comments
 (0)