X-Git-Url: https://git.adam-barratt.org.uk/?a=blobdiff_plain;f=userdir_gpg.py;h=abe1708cbf1f604a6dbd62597a45d26722a43f33;hb=9074893cdd1396b213882989b1b2c0f698af7e56;hp=9b497b29a88510fdcd8970f8d1f70563ae542dd0;hpb=cdba05cbc8f2fa6a8557fd43e6c4e4d5d8e1130c;p=mirror%2Fuserdir-ldap.git diff --git a/userdir_gpg.py b/userdir_gpg.py index 9b497b2..abe1708 100644 --- a/userdir_gpg.py +++ b/userdir_gpg.py @@ -52,6 +52,9 @@ CleanCutOff = 7*24*60*60; AgeCutOff = 4*24*60*60; FutureCutOff = 3*24*60*60; +def ClearKeyrings(): + del GPGKeyRings[:] + # Set the keyrings, the input is a list of keyrings def SetKeyrings(Rings): for x in Rings: @@ -254,11 +257,20 @@ def GPGWriteFilter(Program,Options,Message): # It is best if the recipient is specified using the hex key fingerprint # of the target, ie 0x64BE1319CCF6D393BF87FF9358A6D4EE def GPGEncrypt(Message,To,PGP2): + Error = "KeyringError" # Encrypt using the PGP5 block encoding and with the PGP5 option set. # This will handle either RSA or DSA/DH asymetric keys. # In PGP2 compatible mode IDEA and rfc1991 encoding are used so that # PGP2 can read the result. RSA keys do not need PGP2 to be set, as GPG # can read a message encrypted with blowfish and RSA. + searchkey = GPGKeySearch(To); + if len(searchkey) == 0: + raise Error, "No key found matching %s"%(To); + elif len(searchkey) > 1: + raise Error, "Multiple keys found matching %s"%(To); + if searchkey[0][4].find("E") < 0: + raise Error, "Key %s has no encryption capability - are all encryption subkeys expired or revoked? Are there any encryption subkeys?"%(To); + if PGP2 == 0: try: Res = None; @@ -343,7 +355,15 @@ def GPGCheckSig(Message): GoodSig = 1; KeyID = Split[2]; Owner = ' '.join(Split[3:]) - + # If this message is signed with a subkey which has not yet + # expired, GnuPG will say GOODSIG here, even if the primary + # key already has expired. This came up in discussion of + # bug #489225. GPGKeySearch only returns non-expired keys. + Verify = GPGKeySearch(KeyID); + if len(Verify) == 0: + GoodSig = 0 + Why = "Key has expired (no unexpired key found in keyring matching %s)"%(KeyId); + # Bad signature response if Split[1] == "BADSIG": GoodSig = 0; @@ -368,10 +388,15 @@ def GPGCheckSig(Message): Why = "Unable to verify signature, signing key missing."; # Expired signature - if Split[1] == "SIGEXPIRED" or Split[1] == "EXPSIG": + if Split[1] == "EXPSIG": GoodSig = 0; Why = "Signature has expired"; - + + # Expired signature + if Split[1] == "EXPKEYSIG": + GoodSig = 0; + Why = "Signing key (%s, %s) has expired"%(Split[2], Split[3]); + # Revoked key if Split[1] == "KEYREVOKED" or Split[1] == "REVKEYSIG": GoodSig = 0; @@ -401,7 +426,7 @@ def GPGCheckSig(Message): # A gpg failure is an automatic bad signature if Exit[1] != 0 and Why == None: GoodSig = 0; - Why = "GPG execution failed " + str(Exit[0]); + Why = "GPG execution returned non-zero exit status: " + str(Exit[1]); if GoodSig == 0 and (Why == None or len(Why) == 0): Why = "Checking Failed"; @@ -417,10 +442,32 @@ def GPGCheckSig(Message): Res[1].close(); Res[2].close(); +class GPGCheckSig2: + def __init__(self, msg): + res = GPGCheckSig(msg) + self.why = res[0] + self.sig_info = res[1] + self.key_info = res[2] + self.text = res[3] + + self.ok = self.why is None + + self.sig_id = self.sig_info[0] + self.sig_date = self.sig_info[1] + self.sig_fpr = self.sig_info[2] + + self.key_id = self.key_info[0] + self.key_fpr = self.key_info[1] + self.key_owner = self.key_info[2] + + self.is_pgp2 = self.key_info[4] + # Search for keys given a search pattern. The pattern is passed directly # to GPG for processing. The result is a list of tuples of the form: # (KeyID,KeyFinger,Owner,Length) # Which is similar to the key identification tuple output by GPGChecksig +# +# Do not return keys where the primary key has expired def GPGKeySearch(SearchCriteria): Args = [GPGPath] + GPGBasicOptions + GPGKeyRings + GPGSearchOptions + \ [SearchCriteria," 2> /dev/null"] @@ -428,6 +475,8 @@ def GPGKeySearch(SearchCriteria): Result = []; Owner = ""; KeyID = ""; + Capabilities = "" + Expired = None; Hits = {}; dir = os.path.expanduser("~/.gnupg") @@ -448,14 +497,17 @@ def GPGKeySearch(SearchCriteria): if Split[0] == 'pub': KeyID = Split[4]; Owner = Split[9]; - Length = int(Split[2]); + Length = int(Split[2]) + Capabilities = Split[11] + Expired = Split[1] == 'e' # Output the key if Split[0] == 'fpr': if Hits.has_key(Split[9]): continue; Hits[Split[9]] = None; - Result.append( (KeyID,Split[9],Owner,Length) ); + if not Expired: + Result.append( (KeyID,Split[9],Owner,Length,Capabilities) ); finally: if Strm != None: Strm.close(); @@ -536,3 +588,6 @@ class ReplayCache: else: self.DB[Key] = str(int(Sig[1])); +# vim:set et: +# vim:set ts=3: +# vim:set shiftwidth=3: