33package signature
44
55import (
6+ "bytes"
7+ "context"
8+ "io"
69 "os"
710
811 "github.com/proglottis/gpgme"
@@ -12,7 +15,7 @@ import (
1215// recognizes _only_ public keys from the supplied blobs, and returns the identities
1316// of these keys.
1417// The caller must call .Close() on the returned SigningMechanism.
15- func newEphemeralGPGSigningMechanism (blobs [][]byte ) (signingMechanismWithPassphrase , []string , error ) {
18+ func newEphemeralGPGSigningMechanism (ctx context. Context , blobs [][]byte ) (signingMechanismWithPassphrase , []string , error ) {
1619 dir , err := os .MkdirTemp ("" , "containers-ephemeral-gpg-" )
1720 if err != nil {
1821 return nil , nil , err
@@ -23,34 +26,61 @@ func newEphemeralGPGSigningMechanism(blobs [][]byte) (signingMechanismWithPassph
2326 os .RemoveAll (dir )
2427 }
2528 }()
26- ctx , err := newGPGMEContext (dir )
29+ gpgmeCtx , err := newGPGMEContext (dir )
2730 if err != nil {
2831 return nil , nil , err
2932 }
3033 keyIdentities := []string {}
3134 for _ , blob := range blobs {
32- ki , err := importKeysFromBytes (ctx , blob )
35+ ki , err := importKeysFromBytes (ctx , gpgmeCtx , blob )
3336 if err != nil {
3437 return nil , nil , err
3538 }
3639 keyIdentities = append (keyIdentities , ki ... )
3740 }
3841
39- mech := newGPGMESigningMechanism (ctx , dir )
42+ mech := newGPGMESigningMechanism (gpgmeCtx , dir )
4043 removeDir = false
4144 return mech , keyIdentities , nil
4245}
4346
47+ // cancelableReader wraps an io.Reader and checks context cancellation on each Read call.
48+ type cancelableReader struct {
49+ ctx context.Context
50+ reader io.Reader
51+ }
52+
53+ func (r * cancelableReader ) Read (p []byte ) (int , error ) {
54+ // Check if context is cancelled before each read
55+ if err := r .ctx .Err (); err != nil {
56+ return 0 , err
57+ }
58+ n , err := r .reader .Read (p )
59+ // Check again after read in case cancellation happened during the read
60+ if err == nil && r .ctx .Err () != nil {
61+ return n , r .ctx .Err ()
62+ }
63+ return n , err
64+ }
65+
4466// importKeysFromBytes imports public keys from the supplied blob and returns their identities.
4567// The blob is assumed to have an appropriate format (the caller is expected to know which one).
4668// NOTE: This may modify long-term state (e.g. key storage in a directory underlying the mechanism);
4769// but we do not make this public, it can only be used through newEphemeralGPGSigningMechanism.
48- func importKeysFromBytes (ctx * gpgme.Context , blob []byte ) ([]string , error ) {
49- inputData , err := gpgme .NewDataBytes (blob )
70+ // The context can be used to cancel the operation; if cancelled, the reader will return an error
71+ // which may allow the GPGME operation to abort (though there's no guarantee the C library will
72+ // respect this immediately).
73+ func importKeysFromBytes (ctx context.Context , gpgmeCtx * gpgme.Context , blob []byte ) ([]string , error ) {
74+ // Create a cancelable reader that checks context on each Read call
75+ reader := & cancelableReader {
76+ ctx : ctx ,
77+ reader : bytes .NewReader (blob ),
78+ }
79+ inputData , err := gpgme .NewDataReader (reader )
5080 if err != nil {
5181 return nil , err
5282 }
53- res , err := ctx .Import (inputData )
83+ res , err := gpgmeCtx .Import (inputData )
5484 if err != nil {
5585 return nil , err
5686 }
0 commit comments