28
28
29
29
from sigstore import __version__
30
30
from sigstore ._internal .ctfe import CTKeyring
31
- from sigstore ._internal .fulcio .client import DEFAULT_FULCIO_URL , FulcioClient
31
+ from sigstore ._internal .fulcio .client import (
32
+ DEFAULT_FULCIO_URL ,
33
+ ExpiredCertificate ,
34
+ FulcioClient ,
35
+ )
32
36
from sigstore ._internal .keyring import Keyring
37
+ from sigstore ._internal .oidc import ExpiredIdentity
33
38
from sigstore ._internal .rekor .client import (
34
39
DEFAULT_REKOR_URL ,
35
40
RekorClient ,
44
49
Issuer ,
45
50
detect_credential ,
46
51
)
47
- from sigstore .sign import Signer
52
+ from sigstore .sign import SigningContext
48
53
from sigstore .transparency import LogEntry
49
54
from sigstore .verify import (
50
55
CertificateVerificationFailure ,
@@ -330,10 +335,11 @@ def _parser() -> argparse.ArgumentParser:
330
335
help = "Overwrite preexisting signature and certificate outputs, if present" ,
331
336
)
332
337
output_options .add_argument (
333
- "--single-cert" ,
338
+ "--no-cache" ,
339
+ dest = "no_cache" ,
334
340
action = "store_true" ,
335
- default = _boolify_env ("SIGSTORE_SINGLE_CERT " ),
336
- help = "Use a single signing certificate and key to sign multiple artifacts " ,
341
+ default = _boolify_env ("SIGSTORE_NO_CACHE " ),
342
+ help = "Generate a new signing certificate and private key for each artifact signed " ,
337
343
)
338
344
339
345
instance_options = sign .add_argument_group ("Sigstore instance options" )
@@ -617,13 +623,13 @@ def _sign(args: argparse.Namespace) -> None:
617
623
"bundle" : bundle ,
618
624
}
619
625
620
- # Select the signer to use.
626
+ # Select the signing context to use.
621
627
if args .staging :
622
628
logger .debug ("sign: staging instances requested" )
623
- signer = Signer .staging (single_certificate = args . single_cert )
629
+ signing_ctx = SigningContext .staging ()
624
630
args .oidc_issuer = STAGING_OAUTH_ISSUER_URL
625
631
elif args .fulcio_url == DEFAULT_FULCIO_URL and args .rekor_url == DEFAULT_REKOR_URL :
626
- signer = Signer .production (single_certificate = args . single_cert )
632
+ signing_ctx = SigningContext .production ()
627
633
else :
628
634
# Assume "production" keys if none are given as arguments
629
635
updater = TrustUpdater .production ()
@@ -639,10 +645,9 @@ def _sign(args: argparse.Namespace) -> None:
639
645
ct_keyring = CTKeyring (Keyring (ctfe_keys ))
640
646
rekor_keyring = RekorKeyring (Keyring (rekor_keys ))
641
647
642
- signer = Signer (
648
+ signing_ctx = SigningContext (
643
649
fulcio = FulcioClient (args .fulcio_url ),
644
650
rekor = RekorClient (args .rekor_url , rekor_keyring , ct_keyring ),
645
- single_certificate = args .single_cert ,
646
651
)
647
652
648
653
# The order of precedence is as follows:
@@ -655,38 +660,51 @@ def _sign(args: argparse.Namespace) -> None:
655
660
if not args .identity_token :
656
661
args ._parser .error ("No identity token supplied or detected!" )
657
662
658
- for file , outputs in output_map .items ():
659
- logger .debug (f"signing for { file .name } " )
660
- with file .open (mode = "rb" , buffering = 0 ) as io :
661
- result = signer .sign (
662
- input_ = io ,
663
- identity_token = args .identity_token ,
663
+ cache = not args .no_cache
664
+ with signing_ctx .with_signer (
665
+ identity_token = args .identity_token , cache = cache
666
+ ) as signer :
667
+ for file , outputs in output_map .items ():
668
+ logger .debug (f"signing for { file .name } " )
669
+ with file .open (mode = "rb" , buffering = 0 ) as io :
670
+ try :
671
+ result = signer .sign (
672
+ input_ = io , rekor = signing_ctx ._rekor , fulcio = signing_ctx ._fulcio
673
+ )
674
+ except ExpiredIdentity as exp_identity :
675
+ print ("Signature failed: identity token has expired" )
676
+ raise exp_identity
677
+
678
+ except ExpiredCertificate as exp_certificate :
679
+ print ("Signature failed: Fulcio signing certificate has expired" )
680
+ raise exp_certificate
681
+
682
+ print ("Using ephemeral certificate:" )
683
+ print (result .cert_pem )
684
+
685
+ print (
686
+ f"Transparency log entry created at index: { result .log_entry .log_index } "
664
687
)
665
688
666
- print ("Using ephemeral certificate:" )
667
- print (result .cert_pem )
668
-
669
- print (f"Transparency log entry created at index: { result .log_entry .log_index } " )
670
-
671
- sig_output : TextIO
672
- if outputs ["sig" ] is not None :
673
- sig_output = outputs ["sig" ].open ("w" )
674
- else :
675
- sig_output = sys .stdout
689
+ sig_output : TextIO
690
+ if outputs ["sig" ] is not None :
691
+ sig_output = outputs ["sig" ].open ("w" )
692
+ else :
693
+ sig_output = sys .stdout
676
694
677
- print (result .b64_signature , file = sig_output )
678
- if outputs ["sig" ] is not None :
679
- print (f"Signature written to { outputs ['sig' ]} " )
695
+ print (result .b64_signature , file = sig_output )
696
+ if outputs ["sig" ] is not None :
697
+ print (f"Signature written to { outputs ['sig' ]} " )
680
698
681
- if outputs ["cert" ] is not None :
682
- with outputs ["cert" ].open (mode = "w" ) as io :
683
- print (result .cert_pem , file = io )
684
- print (f"Certificate written to { outputs ['cert' ]} " )
699
+ if outputs ["cert" ] is not None :
700
+ with outputs ["cert" ].open (mode = "w" ) as io :
701
+ print (result .cert_pem , file = io )
702
+ print (f"Certificate written to { outputs ['cert' ]} " )
685
703
686
- if outputs ["bundle" ] is not None :
687
- with outputs ["bundle" ].open (mode = "w" ) as io :
688
- print (result ._to_bundle ().to_json (), file = io )
689
- print (f"Sigstore bundle written to { outputs ['bundle' ]} " )
704
+ if outputs ["bundle" ] is not None :
705
+ with outputs ["bundle" ].open (mode = "w" ) as io :
706
+ print (result ._to_bundle ().to_json (), file = io )
707
+ print (f"Sigstore bundle written to { outputs ['bundle' ]} " )
690
708
691
709
692
710
def _collect_verification_state (
0 commit comments