|
20 | 20 | import logging
|
21 | 21 | import os
|
22 | 22 | import sys
|
23 |
| -from concurrent import futures |
24 | 23 | from dataclasses import dataclass
|
25 | 24 | from pathlib import Path
|
26 |
| -from typing import Any, NoReturn, Union |
| 25 | +from typing import Any, NoReturn, TextIO, Union |
27 | 26 |
|
28 | 27 | from cryptography.hazmat.primitives.serialization import Encoding
|
29 | 28 | from cryptography.x509 import load_pem_x509_certificate
|
|
57 | 56 | Issuer,
|
58 | 57 | detect_credential,
|
59 | 58 | )
|
60 |
| -from sigstore.sign import Signer, SigningContext |
| 59 | +from sigstore.sign import SigningContext |
61 | 60 | from sigstore.verify import (
|
62 | 61 | Verifier,
|
63 | 62 | policy,
|
@@ -637,57 +636,6 @@ def _get_identity_token(args: argparse.Namespace) -> None:
|
637 | 636 | _invalid_arguments(args, "No identity token supplied or detected!")
|
638 | 637 |
|
639 | 638 |
|
640 |
| -def _sign_file_threaded( |
641 |
| - signer: Signer, |
642 |
| - predicate_type: str | None, |
643 |
| - predicate: dict[str, Any] | None, |
644 |
| - file: Path, |
645 |
| - outputs: SigningOutputs, |
646 |
| -) -> None: |
647 |
| - """sign method to be called from signing thread""" |
648 |
| - _logger.debug(f"signing for {file.name}") |
649 |
| - with file.open(mode="rb") as io: |
650 |
| - # The input can be indefinitely large, so we perform a streaming |
651 |
| - # digest and sign the prehash rather than buffering it fully. |
652 |
| - digest = sha256_digest(io) |
653 |
| - try: |
654 |
| - if predicate is None: |
655 |
| - result = signer.sign_artifact(input_=digest) |
656 |
| - else: |
657 |
| - subject = Subject(name=file.name, digest={"sha256": digest.digest.hex()}) |
658 |
| - statement_builder = StatementBuilder( |
659 |
| - subjects=[subject], |
660 |
| - predicate_type=predicate_type, |
661 |
| - predicate=predicate, |
662 |
| - ) |
663 |
| - result = signer.sign_dsse(statement_builder.build()) |
664 |
| - except ExpiredIdentity as exp_identity: |
665 |
| - _logger.error("Signature failed: identity token has expired") |
666 |
| - raise exp_identity |
667 |
| - |
668 |
| - except ExpiredCertificate as exp_certificate: |
669 |
| - _logger.error("Signature failed: Fulcio signing certificate has expired") |
670 |
| - raise exp_certificate |
671 |
| - |
672 |
| - _logger.info( |
673 |
| - f"Transparency log entry created at index: {result.log_entry.log_index}" |
674 |
| - ) |
675 |
| - |
676 |
| - if outputs.signature is not None: |
677 |
| - signature = base64.b64encode(result.signature).decode() |
678 |
| - with outputs.signature.open(mode="w") as io: |
679 |
| - print(signature, file=io) |
680 |
| - |
681 |
| - if outputs.certificate is not None: |
682 |
| - cert_pem = signer._signing_cert().public_bytes(Encoding.PEM).decode() |
683 |
| - with outputs.certificate.open(mode="w") as io: |
684 |
| - print(cert_pem, file=io) |
685 |
| - |
686 |
| - if outputs.bundle is not None: |
687 |
| - with outputs.bundle.open(mode="w") as io: |
688 |
| - print(result.to_json(), file=io) |
689 |
| - |
690 |
| - |
691 | 639 | def _sign_common(
|
692 | 640 | args: argparse.Namespace, output_map: OutputMap, predicate: dict[str, Any] | None
|
693 | 641 | ) -> None:
|
@@ -718,37 +666,63 @@ def _sign_common(
|
718 | 666 | if not identity:
|
719 | 667 | _invalid_arguments(args, "No identity token supplied or detected!")
|
720 | 668 |
|
721 |
| - # Not all commands provide --predicate-type |
722 |
| - predicate_type = getattr(args, "predicate_type", None) |
723 |
| - |
724 | 669 | with signing_ctx.signer(identity) as signer:
|
725 |
| - print("Using ephemeral certificate:") |
726 |
| - cert_pem = signer._signing_cert().public_bytes(Encoding.PEM).decode() |
727 |
| - print(cert_pem) |
728 |
| - |
729 |
| - # sign in threads: this is relevant for especially Rekor v2 as otherwise we wait |
730 |
| - # for log inclusion for each signature separately |
731 |
| - with futures.ThreadPoolExecutor() as executor: |
732 |
| - jobs = [ |
733 |
| - executor.submit( |
734 |
| - _sign_file_threaded, |
735 |
| - signer, |
736 |
| - predicate_type, |
737 |
| - predicate, |
738 |
| - file, |
739 |
| - outputs, |
740 |
| - ) |
741 |
| - for file, outputs in output_map.items() |
742 |
| - ] |
743 |
| - for job in futures.as_completed(jobs): |
744 |
| - job.result() |
745 |
| - |
746 | 670 | for file, outputs in output_map.items():
|
| 671 | + _logger.debug(f"signing for {file.name}") |
| 672 | + with file.open(mode="rb") as io: |
| 673 | + # The input can be indefinitely large, so we perform a streaming |
| 674 | + # digest and sign the prehash rather than buffering it fully. |
| 675 | + digest = sha256_digest(io) |
| 676 | + try: |
| 677 | + if predicate is None: |
| 678 | + result = signer.sign_artifact(input_=digest) |
| 679 | + else: |
| 680 | + subject = Subject( |
| 681 | + name=file.name, digest={"sha256": digest.digest.hex()} |
| 682 | + ) |
| 683 | + predicate_type = args.predicate_type |
| 684 | + statement_builder = StatementBuilder( |
| 685 | + subjects=[subject], |
| 686 | + predicate_type=predicate_type, |
| 687 | + predicate=predicate, |
| 688 | + ) |
| 689 | + result = signer.sign_dsse(statement_builder.build()) |
| 690 | + except ExpiredIdentity as exp_identity: |
| 691 | + print("Signature failed: identity token has expired") |
| 692 | + raise exp_identity |
| 693 | + |
| 694 | + except ExpiredCertificate as exp_certificate: |
| 695 | + print("Signature failed: Fulcio signing certificate has expired") |
| 696 | + raise exp_certificate |
| 697 | + |
| 698 | + print("Using ephemeral certificate:") |
| 699 | + cert = result.signing_certificate |
| 700 | + cert_pem = cert.public_bytes(Encoding.PEM).decode() |
| 701 | + print(cert_pem) |
| 702 | + |
| 703 | + print( |
| 704 | + f"Transparency log entry created at index: {result.log_entry.log_index}" |
| 705 | + ) |
| 706 | + |
| 707 | + sig_output: TextIO |
| 708 | + if outputs.signature is not None: |
| 709 | + sig_output = outputs.signature.open("w") |
| 710 | + else: |
| 711 | + sig_output = sys.stdout |
| 712 | + |
| 713 | + signature = base64.b64encode(result.signature).decode() |
| 714 | + print(signature, file=sig_output) |
747 | 715 | if outputs.signature is not None:
|
748 | 716 | print(f"Signature written to {outputs.signature}")
|
| 717 | + |
749 | 718 | if outputs.certificate is not None:
|
| 719 | + with outputs.certificate.open(mode="w") as io: |
| 720 | + print(cert_pem, file=io) |
750 | 721 | print(f"Certificate written to {outputs.certificate}")
|
| 722 | + |
751 | 723 | if outputs.bundle is not None:
|
| 724 | + with outputs.bundle.open(mode="w") as io: |
| 725 | + print(result.to_json(), file=io) |
752 | 726 | print(f"Sigstore bundle written to {outputs.bundle}")
|
753 | 727 |
|
754 | 728 |
|
|
0 commit comments