# packets so I can tell if a signature is made by pgp2 to enable the
# pgp2 encrypting mode.
-import string, mimetools, multifile, sys, StringIO, os, tempfile, re;
+import mimetools, multifile, sys, StringIO, os, tempfile, re;
import rfc822, time, fcntl, anydbm
# General GPG options
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:
while 1:
x = mf.readline();
if not x: break;
- if len(string.strip(x)) != 0:
+ if len(x.strip()) != 0:
raise Error,"Unsigned text in message (at start)";
mf.seek(Pos);
InnerMsg = mimetools.Message(mf);
if InnerMsg.gettype() != "application/pgp-signature":
raise Error, "Invalid pgp/mime encoding [wrong signature type]";
- Signature = string.joinfields(mf.readlines(),'');
+ Signature = ''.join(mf.readlines())
# Check the last bit of the message..
if Paranoid != 0:
while 1:
x = mf.readline();
if not x: break;
- if len(string.strip(x)) != 0:
+ if len(x.strip()) != 0:
raise Error,"Unsigned text in message (at end)";
mf.seek(Pos);
Output = "-----BEGIN PGP SIGNED MESSAGE-----\r\n";
# Semi-evil hack to get the proper hash type inserted in the message
if Msg.getparam('micalg') != None:
- Output = Output + "Hash: MD5,SHA1,%s\r\n"%(string.upper(Msg.getparam('micalg')[4:]));
+ Output = Output + "Hash: MD5,SHA1,%s\r\n"%(Msg.getparam('micalg')[4:].upper())
Output = Output + "\r\n";
- Output = Output + string.replace(Signed.getvalue(),"\n-","\n- -") + Signature;
+ Output = Output + Signed.getvalue().replace("\n-","\n- -") + Signature
return (Output,1);
else:
if Paranoid == 0:
# Just return the message body
- return (string.joinfields(Msg.fp.readlines(),''),0);
+ return (''.join(Msg.fp.readlines()),0);
Body = "";
State = 1;
for x in Msg.fp.readlines():
Body = Body + x;
- Tmp = string.strip(x);
+ Tmp = x.strip()
if len(Tmp) == 0:
continue;
# 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;
if Why == None:
GoodSig = 1;
KeyID = Split[2];
- Owner = string.join(Split[3:],' ');
-
+ 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;
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;
# 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";
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"]
Result = [];
Owner = "";
KeyID = "";
+ Capabilities = ""
+ Expired = None;
Hits = {};
dir = os.path.expanduser("~/.gnupg")
os.mkdir(dir, 0700)
try:
- Strm = os.popen(string.join(Args," "),"r");
+ Strm = os.popen(" ".join(Args),"r")
while(1):
# Grab and split up line
Line = Strm.readline();
if Line == "":
break;
- Split = string.split(Line,":");
-
- # Store some of the key fields
+ Split = Line.split(":")
+
+ # Store some of the key fields
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();
# Perform a substition of template
def TemplateSubst(Map,Template):
for x in Map.keys():
- Template = string.replace(Template,x,Map[x]);
+ Template = Template.replace(x, Map[x])
return Template;
# The replay class uses a python DB (BSD db if avail) to implement
else:
self.DB[Key] = str(int(Sig[1]));
+# vim:set et:
+# vim:set ts=3:
+# vim:set shiftwidth=3: