@@ -98,27 +98,62 @@ func shouldPreferIdentity(existingId, potentialNewId *packet.Signature) bool {
9898// EncryptionKey returns the best candidate Key for encrypting a message to the
9999// given Entity.
100100func (e * Entity ) EncryptionKey (now time.Time , config * packet.Config ) (Key , bool ) {
101+ encryptionKey , err := e .EncryptionKeyWithError (now , config )
102+ return encryptionKey , err == nil
103+ }
104+
105+ // EncryptionKeyWithError returns the best candidate Key for encrypting a message to the
106+ // given Entity.
107+ // Provides an error if the function fails to find an encryption key.
108+ func (e * Entity ) EncryptionKeyWithError (now time.Time , config * packet.Config ) (Key , error ) {
101109 // The primary key has to be valid at time now
102110 primarySelfSignature , err := e .VerifyPrimaryKey (now , config )
103111 if err != nil { // primary key is not valid
104- return Key {}, false
112+ return Key {}, errors.ErrEncryptionKeySelection {
113+ PrimaryKeyId : e .PrimaryKey .KeyIdString (),
114+ PrimaryKeyErr : err ,
115+ }
105116 }
106117
107- if checkKeyRequirements (e .PrimaryKey , config ) != nil {
118+ if err := checkKeyRequirements (e .PrimaryKey , config ); err != nil {
108119 // The primary key produces weak signatures
109- return Key {}, false
120+ return Key {}, errors.ErrEncryptionKeySelection {
121+ PrimaryKeyId : e .PrimaryKey .KeyIdString (),
122+ PrimaryKeyErr : err ,
123+ }
110124 }
111125
112126 // Iterate the keys to find the newest, unexpired one
127+ var latestSelectionError * errors.ErrEncryptionKeySelection
113128 candidateSubkey := - 1
114129 var maxTime time.Time
115130 var selectedSubkeySelfSig * packet.Signature
116131 for i , subkey := range e .Subkeys {
132+ subkeyErr := func (encSelectionErr error ) * errors.ErrEncryptionKeySelection {
133+ subkeyKeyId := subkey .PublicKey .KeyIdString ()
134+ return & errors.ErrEncryptionKeySelection {
135+ PrimaryKeyId : e .PrimaryKey .KeyIdString (),
136+ EncSelectionKeyId : & subkeyKeyId ,
137+ EncSelectionErr : encSelectionErr ,
138+ }
139+
140+ }
141+ // Verify the subkey signature.
117142 subkeySelfSig , err := subkey .Verify (now , config ) // subkey has to be valid at time now
118- if err == nil &&
119- isValidEncryptionKey (subkeySelfSig , subkey .PublicKey .PubKeyAlgo , config ) &&
120- checkKeyRequirements (subkey .PublicKey , config ) == nil &&
121- (maxTime .IsZero () || subkeySelfSig .CreationTime .Unix () >= maxTime .Unix ()) {
143+ if err != nil {
144+ latestSelectionError = subkeyErr (err )
145+ continue
146+ }
147+ // Check the algorithm and key flags.
148+ if ! isValidEncryptionKey (subkeySelfSig , subkey .PublicKey .PubKeyAlgo , config ) {
149+ continue
150+ }
151+ // Check if the key fulfils the requirements
152+ if err := checkKeyRequirements (subkey .PublicKey , config ); err != nil {
153+ latestSelectionError = subkeyErr (err )
154+ continue
155+ }
156+ if maxTime .IsZero () || subkeySelfSig .CreationTime .Unix () >= maxTime .Unix () {
122157 candidateSubkey = i
123158 selectedSubkeySelfSig = subkeySelfSig
124159 maxTime = subkeySelfSig .CreationTime
@@ -133,7 +168,7 @@ func (e *Entity) EncryptionKey(now time.Time, config *packet.Config) (Key, bool)
133168 PublicKey : subkey .PublicKey ,
134169 PrivateKey : subkey .PrivateKey ,
135170 SelfSignature : selectedSubkeySelfSig ,
136- }, true
171+ }, nil
137172 }
138173
139174 // If we don't have any subkeys for encryption and the primary key
@@ -145,10 +180,17 @@ func (e *Entity) EncryptionKey(now time.Time, config *packet.Config) (Key, bool)
145180 PublicKey : e .PrimaryKey ,
146181 PrivateKey : e .PrivateKey ,
147182 SelfSignature : primarySelfSignature ,
148- }, true
183+ }, nil
184+ }
185+
186+ if latestSelectionError == nil {
187+ latestSelectionError = & errors.ErrEncryptionKeySelection {
188+ PrimaryKeyId : e .PrimaryKey .KeyIdString (),
189+ EncSelectionErr : goerrors .New ("no encryption-capable key found (no key flags or invalid algorithm)" ),
190+ }
149191 }
150192
151- return Key {}, false
193+ return Key {}, latestSelectionError
152194}
153195
154196// DecryptionKeys returns all keys that are available for decryption, matching the keyID when given
0 commit comments