[mnet-devel] patch (incomplete): cleaning up persistent data storage
Zooko
zooko at zooko.com
Sat Feb 1 03:32:06 GMT 2003
Because there is a bug in mesgen.py's use of bsddb which results in a database
that cannot be loaded, I've started a long-desired clean-up of all the
persistent storage stuff in mesgen.py and counterparties.py. Actually I haven't
gotten to counterparties.py yet. The patch is incomplete, so I won't commit it,
but I will append it to this message so interested people can see the kind of
thing that are changing. I used context diff instead of unified diff because
for changes of this kind "side by side" comparison is better than "interlaced"
comparison.
The general theme to look for is that the "after" part of each diff hunk is
shorter than the "before" part. If you look more closely you can see weird
bsddb things being replaced with nice normal Python dicts.
Regards,
Zooko
Index: egtp/MojoTransaction.py
===================================================================
RCS file: /cvsroot/egtp/egtp_new/egtp/MojoTransaction.py,v
retrieving revision 1.22
diff -c -r1.22 MojoTransaction.py
*** egtp/MojoTransaction.py 7 Jan 2003 19:51:29 -0000 1.22
--- egtp/MojoTransaction.py 1 Feb 2003 03:29:12 -0000
***************
*** 127,152 ****
MIN_HELLO_DELAY=45 # never send hellos to MTs more often than this, even if you have new contact info
MIN_REDUNDANT_HELLO_DELAY=450 # never send the same contact info to MTs more often than this
class MojoTransactionManager:
"""
! There are basically two interfaces to MojoTransactionManager, one for
! handling transactions initiated by you and satisfied by a remote broker
! acting as a server, and one for handling transactions initiated by a remote
! broker acting as client and satisfied by you.
!
! If you want to handle incoming request messages (for example, you are a
! block server and you want to handle incoming 'get block' messages), then you
! define a handler func, which is a function that takes two arguments named
! 'widget' and 'msgbody', and returns either a tuple of (response, commhints)
! or else an instance of ResponseMarker. The response, if any, will be sent
! back to the client. See the documentation for the ResponseMarkers, above.
!
! If you want to initiate a transaction with a remote broker acting as server,
! call `MojoTransactionManager.initiate()', passing the id of the remote
! broker, the contents of the query message, and optionally a callback
! function that will be called when the transaction completes or fails.
"""
! def __init__(self, lookupman, discoveryman, datadir, use_dynamic_timing = true, pt=None, announced_service_dicts=[], handler_funcs={}, serialized=None, ip_bind=None, listenport=None, recoverdb=true, pickyport=false, dontbind=false, neverpoll=false, keyID=None, allow_send_metainfo=true, allownonrouteableip=false):
"""
@param lookupman: an object which implements the ILookupManager
interface; MojoTransaction uses the lookupman to get fresh EGTP
--- 127,178 ----
MIN_HELLO_DELAY=45 # never send hellos to MTs more often than this, even if you have new contact info
MIN_REDUNDANT_HELLO_DELAY=450 # never send the same contact info to MTs more often than this
+
+ global sillyflag
+ sillyflag = true # silly! (This is to prevent people from instantiating MojoTransactionManager with its constructor instead of with one of the following two factory functions.)
+ def new_MTM(lookupman, discoveryman, datadir, use_dynamic_timing=true, announced_service_dicts=[], handler_funcs={}, ip_bind=None, listenport=None, pickyport=false, dontbind=false, neverpoll=false, allow_send_metainfo=true, allownonrouteableip=false):
+ """
+ Creates an MTM that has never existed before.
+
+ @deprecated: in favor of something completely new and nice. That's why I'm not documenting this much. --Zooko 2003-01-31
+ """
+ dbparentdir=os.path.expandvars(datadir)
+ mesgen=mesgen.create_MessageMaker(dbparentdir=dbparentdir)
+ dbparentdir=os.path.expandvars(self._datadir)
+ sillyflag = false
+
+ def load_MTM(lookupman, discoveryman, datadir, keyID, use_dynamic_timing=true, announced_service_dicts=[], handler_funcs={}, ip_bind=None, listenport=None, pickyport=false, dontbind=false, neverpoll=false, allow_send_metainfo=true, allownonrouteableip=false):
+ """
+ Loads an MTM from persistent store.
+
+ @param keyID: This node's egtp id
+
+ @deprecated: in favor of something completely new and nice. That's why I'm not documenting this much. --Zooko 2003-01-31
+ """
+ sillyflag = false
+
class MojoTransactionManager:
"""
! There are basically two interfaces to MojoTransactionManager, one
! for handling transactions initiated by you and satisfied by a remote
! broker acting as a server, and one for handling transactions
! initiated by a remote broker acting as client and satisfied by you.
!
! If you want to handle incoming request messages (for example, you
! are a block server and you want to handle incoming 'get block'
! messages), then you define a handler func, which is a function that
! takes two arguments named 'widget' and 'msgbody', and returns either
! a tuple of (response, commhints) or else an instance of
! ResponseMarker. The response, if any, will be sent back to the
! client. See the documentation for the ResponseMarkers, above.
!
! If you want to initiate a transaction with a remote broker acting as
! server, call `MojoTransactionManager.initiate()', passing the id of
! the remote broker, the contents of the query message, and optionally
! a callback function that will be called when the transaction
! completes or fails.
"""
! def __init__(self, lookupman, discoveryman, datadir, mesgen, use_dynamic_timing = true, pt=None, announced_service_dicts=[], handler_funcs={}, serialized=None, ip_bind=None, listenport=None, recoverdb=true, pickyport=false, dontbind=false, neverpoll=false, allow_send_metainfo=true, allownonrouteableip=false):
"""
@param lookupman: an object which implements the ILookupManager
interface; MojoTransaction uses the lookupman to get fresh EGTP
***************
*** 156,162 ****
IDiscoveryManager interface; MojoTransaction passes this to
RelayListener, which uses the discoveryman to find relay
servers.
- @param keyID: This node's egtp id
@param datadir: directory to store data files created and used by
this object
@param dontbind: `true' if and only if you don't want to bind and
--- 182,187 ----
***************
*** 181,186 ****
--- 206,213 ----
assert isinstance(discoveryman, IDiscoveryManager), "precondition: `discoveryman' must be an instance of interfaces.IDiscoveryManager." + " -- " + "discoveryman: %s :: %s" % (humanreadable.hr(discoveryman), humanreadable.hr(type(discoveryman)),)
assert DoQ.doq.is_currently_doq(), "precondition: This method must be called on the DoQ." + " -- " + "currentThread(): %s" % humanreadable.hr(threading.currentThread())
+ global sillyflag
+ assert not sillyflag, "You are not allowed to call MojoTransaction.MojoTransactionManager() directly. You must call either MojoTransaction.new_MTM() or MojoTransaction.load_MTM()."
self._shuttingdownflag = false
self._lookupman = lookupman
***************
*** 217,240 ****
else:
self._handler_funcs={}
! dbparentdir=os.path.expandvars(self._datadir)
! ready = false
! if keyID:
! try:
! self._mesgen=mesgen.MessageMaker(dir=os.path.join(dbparentdir, keyID), recoverdb=recoverdb)
! ready = true
! except:
! # We sometimes get exceptions here because of corrupted db.
! # "ready" has not yet been set, which means we'll create a
! # whole new db below.
! debugprint("Got exception trying to instantiate mesgen db. Exception and traceback follows:\n");
! traceback.print_exc(file=debugstream)
! pass
!
! if not ready:
! self._mesgen=mesgen.create_MessageMaker(dbparentdir=dbparentdir, recoverdb=recoverdb)
!
! self._dbdir=os.path.join(dbparentdir, idlib.to_mojosixbit(self._mesgen.get_id()))
self.response_times = {}
self._responsetimesold = {}
--- 244,250 ----
else:
self._handler_funcs={}
! self._mesgen=mesgen
self.response_times = {}
self._responsetimesold = {}
***************
*** 476,504 ****
Get our current hello sequence number, incrementing it and
saving it to the config file if it needs updating.
"""
! config = ConfigParser.ConfigParser()
! config.read(os.path.join(self._datadir, 'sequences.conf'))
! asciiid = idlib.to_ascii(self.get_id())
! needtosave = false
! if not config.has_section('sequences'):
! config.add_section('sequences')
! if not config.has_option('sequences', asciiid):
! config.set('sequences', asciiid, 1)
! needtosave = true
! if self.__need_sequence_update:
! self.__need_sequence_update = false
! config.set('sequences', asciiid, int(config.get('sequences', asciiid, raw = true)) + 1)
! needtosave = true
! # wipe the cache of who we've sent metainfo to since it is now false as our metainfo has been updated
! self.__counterparties_metainfo_sent_to_map.clear()
! if needtosave:
! self._contactinfochangedtime = timer.time()
! # save the current sequence number in the config file so that we never lower it
! # (XXX storing it somewhere other than the cfg file such as the mtmdb/<id>/ directory
! # would be a good idea before we implement persistent metainfo... -greg)
! config.write(open(os.path.join(self._datadir, 'sequences.conf'), 'w'))
!
! return int(config.get('sequences', asciiid, raw = true))
def get_contact_info(self):
"""
--- 486,496 ----
Get our current hello sequence number, incrementing it and
saving it to the config file if it needs updating.
"""
! if self._need_sequence_update:
! self._need_sequence_update = false
! self._sequencenum += 1
! self._lazy_save()
! return self._sequencenum
def get_contact_info(self):
"""
Index: egtp/counterparties.py
===================================================================
RCS file: /cvsroot/egtp/egtp_new/egtp/counterparties.py,v
retrieving revision 1.10
diff -c -r1.10 counterparties.py
*** egtp/counterparties.py 12 Jan 2003 20:19:14 -0000 1.10
--- egtp/counterparties.py 1 Feb 2003 03:29:14 -0000
***************
*** 213,227 ****
"""
Individual counterparty objects are NOT threadsafe
"""
! class ExtRes:
! """
! This is for holding things (external resources) that CO needs to
! finalize after CO is killed. (post-mortem finalization)
! """
! def __init__(self):
! pass
! def __del__(self):
! debugprint("%s.__del__(); stack[-6:-1]: %s\n", args=(self, traceback.extract_stack()[-6:-1],), v=5, vs="debug")
def __init__(self, counterparty_id, keeper) :
"""
--- 213,227 ----
"""
Individual counterparty objects are NOT threadsafe
"""
! # class ExtRes:
! # """
! # This is for holding things (external resources) that CO needs to
! # finalize after CO is killed. (post-mortem finalization)
! # """
! # def __init__(self):
! # pass
! # def __del__(self):
! # debugprint("%s.__del__(); stack[-6:-1]: %s\n", args=(self, traceback.extract_stack()[-6:-1],), v=5, vs="debug")
def __init__(self, counterparty_id, keeper) :
"""
Index: egtp/mesgen.py
===================================================================
RCS file: /cvsroot/egtp/egtp_new/egtp/mesgen.py,v
retrieving revision 1.13
diff -c -r1.13 mesgen.py
*** egtp/mesgen.py 18 Jan 2003 20:46:35 -0000 1.13
--- egtp/mesgen.py 1 Feb 2003 03:29:16 -0000
***************
*** 13,31 ****
from cPickle import dumps, loads
import threading, traceback, os, time, types
- from bsddb3 import db, dbobj
-
# pyutil modules
- from pyutil.debugprint import debugprint
from pyutil import Cache
from pyutil import fileutil
# EGTP modules
! from egtp.humanreadable import hr
! from egtp.CleanLogDb import CleanLogDbEnv
from egtp.crypto import modval, tripledescbc, cryptutil, randsource
from egtp import hashrandom, keyutil, idlib, mencode, mojosixbit
true = 1
false = 0
--- 13,35 ----
from cPickle import dumps, loads
import threading, traceback, os, time, types
# pyutil modules
from pyutil import Cache
+ from pyutil import LazySaver
+ from pyutil import compat
+ from pyutil.debugprint import debugprint
from pyutil import fileutil
+ # libbase32 modules
+ from libbase32 import base32
+
# EGTP modules
! from egtp import humanreadable
from egtp.crypto import modval, tripledescbc, cryptutil, randsource
from egtp import hashrandom, keyutil, idlib, mencode, mojosixbit
+ MAXMEMOIZEDHEADERS = 2**6
+
true = 1
false = 0
***************
*** 33,45 ****
SIZE_OF_UNIQS = 20
HARDCODED_RSA_PUBLIC_EXPONENT = 3
-
# Size of public keys generated here-in.
SIZE_OF_PUBLIC_KEYS = SIZE_OF_MODULAR_VALUES
MINS_BETWEEN_DB_CHECKPOINTS = 5
#### !!!! XXXX TODO: add check that counterparty is not using weak public key size. --Zooko 2000-07-16
# Size of symmetric keys.
SIZE_OF_SYMMETRIC_KEYS = 24
--- 37,49 ----
SIZE_OF_UNIQS = 20
HARDCODED_RSA_PUBLIC_EXPONENT = 3
# Size of public keys generated here-in.
SIZE_OF_PUBLIC_KEYS = SIZE_OF_MODULAR_VALUES
MINS_BETWEEN_DB_CHECKPOINTS = 5
#### !!!! XXXX TODO: add check that counterparty is not using weak public key size. --Zooko 2000-07-16
+ # Zooko: keep that issue in mind in EGTPv2. --Zooko 2003-01-30
# Size of symmetric keys.
SIZE_OF_SYMMETRIC_KEYS = 24
***************
*** 57,66 ****
"""
# CryptoCommsHandler catches and uses this
args = 'unknown session id'
! def __init__(self, id_in, counterparty_id):
assert len(id_in) == SIZE_OF_UNIQS
! assert len(counterparty_id) == SIZE_OF_UNIQS
! self.invalidate_session_msg = '\000\000\002\002' + id_in + counterparty_id
# raised by mesgen.parse() when an 'invalidate session' message is received and handled successfully
class SessionInvalidated(Error): pass
--- 61,70 ----
"""
# CryptoCommsHandler catches and uses this
args = 'unknown session id'
! def __init__(self, id_in, counterpartyId):
assert len(id_in) == SIZE_OF_UNIQS
! assert len(counterpartyId) == SIZE_OF_UNIQS
! self.invalidate_session_msg = '\000\000\002\002' + id_in + counterpartyId
# raised by mesgen.parse() when an 'invalidate session' message is received and handled successfully
class SessionInvalidated(Error): pass
***************
*** 76,295 ****
p.pack_string(data)
return sha(p.get_buffer()).digest()
! class SessionKeeper:
! class ExtRes:
! """
! This is for holding things (external resources) that SK needs to
! finalize after SK is killed. (post-mortem finalization)
! """
! def __init__(self, db_env, session_map, counterparty_map):
! self.db_env = db_env
! self.session_map = session_map
! self.counterparty_map = counterparty_map
!
! def __del__(self):
! debugprint("%s.__del__()\n", args=(self,))
! if self.session_map is not None:
! self.session_map.close()
! self.session_map = None
! if self.counterparty_map is not None:
! self.counterparty_map.close()
! self.counterparty_map = None
! if self.db_env is not None:
! debugprint("%s.__del__(): self.db_env.nosyncerror_txn_checkpoint(0)\n", args=(self,))
! self.db_env.nosyncerror_txn_checkpoint(0)
! debugprint("%s.__del__(): self.db_env.close()\n", args=(self,))
! self.db_env.close()
! debugprint("%s.__del__(): self.db_env = None\n", args=(self,))
! self.db_env = None
! debugprint("%s.__del__(): done\n", args=(self,))
!
! def __init__(self, dbparentdir=None, dir=None, serialized = None, maxitems = 1000, recoverdb=true):
! """
! You can pass either dir or dbparentdir, but not both. You pass `dbparentdir' if you
! don't know the id of the key (either because the key is being created or because it is
! being de-serialized). In that case, SessionKeeper creates a new sub-directory of
! dbparentdir which is named by the mojosixbit encoding of the id of the key. For
! example, you pass dbparentdir == "...mtmdb/", and it creates
! "...mtmdb/ABCDEFGHIJKLMNOPQRSTUVWXYZA/" and puts the key in a subdirectory named
! "...mtmdb/ABCDEFGHIJKLMNOPQRSTUVWXYZA/mesgen/".
!
!
! You pass `dir' if you already know the directory that the key is stored in. For
! example, you pass dir == "...mtmdb/ABCDEFGHIJKLMNOPQRSTUVWXYZA/" and it looks in
! "...mtmdb/ABCDEFGHIJKLMNOPQRSTUVWXYZA/mesgen/" and uses the key therein.
!
!
! @param dbparentdir: the directory for all keys; Subdirectories will be located or
! created, named by the mojosixbit encoding of the hash of the key.
! @param dir: the directory for this particular key
!
! @precondition: Exactly one of (dbparentdir, dir) must be not None.: ((dbparentdir is not None) and (dir is None)) or ((dbparentdir is None) and (dir is not None)): "dbparentdir: %s, dir: %s" % (hr(dbparentdir), hr(dir))
! """
! assert ((dbparentdir is not None) and (dir is None)) or ((dbparentdir is None) and (dir is not None)), "precondition: Exactly one of (dbparentdir, dir) must be not None." + " -- " + "dbparentdir: %s, dir: %s" % (hr(dbparentdir), hr(dir))
!
! if serialized:
! debugprint("COMPLAINT: passing in serialized secret keys is the old-style, just-a-hack-for-debug way of doing things. You really want to just give me the directory to start from and I'll get the secret key stored in there in a file.\n", v=3)
!
! if dir:
! # The dbdir is under dir and named "mesgen".
! self._dir = os.path.normpath(dir)
! self._dbdir = os.path.normpath(os.path.join(self._dir, "mesgen"))
!
! if not serialized:
! f = open(os.path.normpath(os.path.join(dir, "key")), "r")
! serialized = f.read()
! f.close()
!
! skdict = mencode.mdecode(serialized)
! keyMV = modval.new_serialized(mojosixbit.a2b(skdict['private key serialized']))
!
! self.__my_public_key = keyutil.makePublicRSAKeyForCommunicating(keyMV)
! self.__my_public_key_id = idlib.make_id(self.__my_public_key, '')
else:
! # The dbdir is under dbparentdir, under my id, and is named "mesgen".
! if serialized:
! skdict = mencode.mdecode(serialized)
! keyMV = modval.new_serialized(mojosixbit.a2b(skdict['private key serialized']))
! else:
! keyMV = modval.new_random(SIZE_OF_PUBLIC_KEYS, HARDCODED_RSA_PUBLIC_EXPONENT)
!
! self.__my_public_key = keyutil.makePublicRSAKeyForCommunicating(keyMV)
! self.__my_public_key_id = idlib.make_id(self.__my_public_key, 'broker')
!
! myid_aa = idlib.to_mojosixbit(self.__my_public_key_id)
!
! self._dir = os.path.normpath(os.path.join(dbparentdir, myid_aa))
! self._dbdir = os.path.normpath(os.path.join(self._dir, "mesgen"))
! fileutil.make_dirs(self._dbdir)
!
! # this lock is used to force single threaded access to this object as we've been having occasional DB_LOCK_DEADLOCK
! # problems with the database, most likely due to TCPCommsHandler accessing it from the asyncore thread as well as
! # CryptoCommsHandler accessing it from the DoQ thread.
! self.lock = threading.Lock()
!
! db_env = CleanLogDbEnv()
! db_env.set_lk_detect(db.DB_LOCK_DEFAULT)
! if recoverdb:
! recoverflag = db.DB_RECOVER
! else:
! recoverflag = 0
!
! privateflag = db.DB_PRIVATE
!
! try:
! db_env.open(self._dbdir, db.DB_CREATE | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_THREAD | db.DB_INIT_LOG | db.DB_INIT_TXN | privateflag | recoverflag)
! except db.DBError, dbe:
! debugprint('Failed to open the database environment the first time, reason: %s\nTrying again...\n', args=(dbe,), vs='mesgen', v=2)
! try:
! db_env.open(self._dbdir, db.DB_CREATE | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_THREAD | db.DB_INIT_LOG | db.DB_INIT_TXN | privateflag | recoverflag | db.DB_RECOVER)
! except db.DBError, dbe:
! debugprint('Failed to open the database environment the second time, reason: %s\nTrying again...\n', args=(dbe,), vs='mesgen', v=2)
! # XXX DOUBLE CHOCOLATEY HACK sometimes trying *again* after one open *without* DB_RECOVER works.
! db_env.open(self._dbdir, db.DB_CREATE | db.DB_INIT_MPOOL | db.DB_INIT_LOCK | db.DB_THREAD | db.DB_INIT_LOG | db.DB_INIT_TXN | privateflag | recoverflag & (~db.DB_RECOVER))
!
! self.__key = keyMV
! # maps id_in to counterparty id
! session_map = dbobj.DB(db_env)
! session_map.open('session_map', db.DB_BTREE, db.DB_CREATE | db.DB_THREAD )
! # maps counterparty id to [session_id_in, session_id_out, symmetric_key, header, full pk]
! # (XXX session_id_in in counterparty_map is never used, that's what session_map is for)
! counterparty_map = dbobj.DB(db_env)
! counterparty_map.open('counterparty_map', db.DB_BTREE, db.DB_CREATE | db.DB_THREAD )
! self.extres = SessionKeeper.ExtRes(db_env, session_map, counterparty_map)
# maps header ids to content of headers for memoization
! self.__cached_headers = Cache.LRUCache(maxitems)
!
! self.store_key(self.__my_public_key)
!
! keyfile = os.path.normpath(os.path.join(self._dir, "key"))
! f = open(keyfile, "w")
! f.write(self.serialize())
! f.close()
! def serialize(self):
! d = {'private key serialized': mojosixbit.b2a(self.__key.get_private_key_encoding())}
! return mencode.mencode(d)
!
! def get_private_key_encoding(self):
! return self.__key.get_private_key_encoding()
def get_public_key(self):
! return self.__my_public_key
!
! def get_public_key_id(self):
! """
! @deprecated: in favor of `get_id()'
! """
! return self.get_id()
def get_id(self):
! return self.__my_public_key_id
! def got_ack(self, counterparty_id):
! self.lock.acquire()
! try:
! return self.__got_ack(counterparty_id)
! finally:
! self.lock.release()
!
! def __got_ack(self, counterparty_id):
"""
Called when a message comes in for a not set up connection.
! @precondition: `counterparty_id' must be an id.: idlib.is_sloppy_id(counterparty_id): "id: %s" % hr(id)
"""
! assert idlib.is_sloppy_id(counterparty_id), "precondition: `counterparty_id' must be an id." + " -- " + "id: %s" % hr(id)
! counterparty_id = idlib.canonicalize(counterparty_id, 'broker')
! self.extres.db_env.nosyncerror_txn_checkpoint(MINS_BETWEEN_DB_CHECKPOINTS)
! trans = self.extres.db_env.txn_begin()
! try:
! # maps counterparty id to [session_id_in, session_id_out, symmetric_key, header, full pk]
! session_id_in, session_id_out, symmetric_key, _header, full_key = loads(self.extres.counterparty_map.get(counterparty_id, txn=trans, flags=db.DB_RMW))[:5]
! # remove the header (to signify our acknowledgement of their session acceptance)
! assert len(symmetric_key) == SIZE_OF_SYMMETRIC_KEYS
! assert keyutil.publicRSAKeyIsSane(full_key)
! assert keyutil.publicKeyForCommunicationSecurityIsWellFormed(full_key)
! self.extres.counterparty_map.put(counterparty_id, dumps([session_id_in, session_id_out, symmetric_key, None, full_key], 1), txn=trans)
! trans.commit()
! trans = None
! finally:
! if trans is not None:
! trans.abort()
!
! def parse_header(self, header):
! self.lock.acquire()
! try:
! return self.__parse_header(header)
! finally:
! self.lock.release()
! def __parse_header(self, header):
"""
Parses a header and stores information contained in it as necessary
Returns (counterparty pub key sexp, symmetric key) throws Error
"""
! assert type(header) == type('')
try:
hash = sha(header).digest()
! cached = self.__cached_headers.get(hash)
if cached is not None:
return cached
u = Unpacker(header)
# messages start with the hash of the recipient's public id
recipient_id = u.unpack_fstring(SIZE_OF_UNIQS)
! if recipient_id != self.__my_public_key_id:
raise Error, 'message not intended for me'
# unpack PK encrypted public key
encrypted_key = u.unpack_string()
! self.__key.set_value_string(encrypted_key)
! self.__key.decrypt() # PKop
! decrypted = self.__key.get_value()
try:
symmetric_key = cryptutil.oaep_decode(decrypted[1:]) # Leave off the initial 0 byte. ### XX check whether it really is 0 and raise bad-encoding error if not. --Zooko 2000-07-29
--- 80,179 ----
p.pack_string(data)
return sha(p.get_buffer()).digest()
! def new_SessionKeeper(dbparentdir):
! keymv = modval.new_random(SIZE_OF_PUBLIC_KEYS, HARDCODED_RSA_PUBLIC_EXPONENT)
! return SessionKeeper(keymv)
!
! def load_SessionKeeper(fname):
! return SessionKeeper(fname)
!
! class SessionKeeper(LazySaver.LazySaver):
! def __init__(self, fname=None, keymv=None):
! """
! @param keymv: the public/private keypair that you just generated, or None if I should load it from fname
! @param fname: the file to load the public/private keypair from, or None if you just generated it and passed it in the keymv parameter
!
! @precondition: Exactly one of (fname, keymv) must be None.: ((fname is not None) and (keymv is None)) or ((fname is None) and (keymv is not None)): "fname: %s, keymv: %s" % tuple(map(humanreadable.hr, (fname, keymv,)))
! """
! assert ((fname is not None) and (keymv is None)) or ((fname is None) and (keymv is not None)), "precondition: " + "Exactly one of (fname, keymv) must be None." + " -- " + "fname: %s, keymv: %s" % tuple(map(humanreadable.hr, (fname, keymv,)))
!
! if keymv:
! # creating a new persistent SessionKeeper instance
! pkIdbase32 = base32.b2a(idlib.make_id(keyutil.makePublicRSAKeyForCommunicating(keymv), 'broker'))
! dir = os.path.normpath(os.path.join(dbparentdir, pkIdbase32))
! fname = os.path.normpath(os.path.join(dir, "sessionkeeper"))
! LazySaver.LazySaver.__init__(fname, {'keymv': keymv, 'sessionmap': {}, 'counterpartymap': {}})
else:
! # loading an old persistent SessionKeeper instance
! LazySaver.LazySaver.__init__(fname)
! assert self.keymv is not None
! assert self.sessionmap is not None
! assert self.counterpartymap is not None
!
! # persistent attributes:
! # self.keymv # a public/private RSA keypair
! # self.sessionmap = {} # maps id_in to counterparty id
! # self.counterpartymap = {} # maps counterparty id to [session_id_in, session_id_out, symmetric_key, header, full pk] (XXX session_id_in in counterparty_map is never used, that's what session_map is for)
! # transient attributes:
# maps header ids to content of headers for memoization
! self._cachedheaders = Cache.LRUCache(MAXMEMOIZEDHEADERS)
! # public key
! self.pk = keyutil.makePublicRSAKeyForCommunicating(self.keymv)
! # public key Id
! self.pkId = idlib.make_id(self.pk, 'broker')
def get_public_key(self):
! return self.pk
def get_id(self):
! return self.pkId
! def got_ack(self, counterpartyId):
"""
Called when a message comes in for a not set up connection.
! @precondition: `counterpartyId' must be an id.: idlib.is_sloppy_id(counterpartyId): "id: %s" % humanreadable.hr(id)
"""
! assert idlib.is_sloppy_id(counterpartyId), "precondition: `counterpartyId' must be an id." + " -- " + "id: %s" %humanreadable. hr(id)
! counterpartyId = idlib.canonicalize(counterpartyId, 'broker')
! # maps counterparty id to [sessionidin, sessionidout, symmetrickey, header, fullpubkey]
! sessionidin, sessionidout, symmetrickey, header, fullpubkey = self.counterpartymap.get(counterpartyId)[:5]
! # remove the header (to signify our acknowledgement of their session acceptance)
! assert len(symmetrickey) == SIZE_OF_SYMMETRIC_KEYS
! assert keyutil.publicRSAKeyIsSane(fullpubkey)
! assert keyutil.publicKeyForCommunicationSecurityIsWellFormed(fullpubkey)
! self.counterpartymap[counterpartyid] = (sessionidin, sessionidout, symmetrickey, None, fullpubkey,)
! self._lazy_save(delay=0) # It is important to save to disk ASAP, as I think losing this information might result in a state where we can *never* talk to this counterparty again. (There is no key renegotiation in EGTPv1.) --Zooko 2003-01-30
! def parse_header(self, header):
"""
Parses a header and stores information contained in it as necessary
Returns (counterparty pub key sexp, symmetric key) throws Error
+
+ @precondition: `header' must be a string.: compat.is_str(header): "header: %s :: %s" % tuple(map(humanreadable.hr, (header, type(header),)))
"""
! assert compat.is_str(header), "precondition: " + "`header' must be a string." + " -- " + "header: %s :: %s" % tuple(map(humanreadable.hr, (header, type(header),)))
try:
hash = sha(header).digest()
! cached = self.cachedheaders.get(hash)
if cached is not None:
return cached
u = Unpacker(header)
# messages start with the hash of the recipient's public id
recipient_id = u.unpack_fstring(SIZE_OF_UNIQS)
! if not idlib.is_equal(recipient_id, self.pkId):
raise Error, 'message not intended for me'
# unpack PK encrypted public key
encrypted_key = u.unpack_string()
! self.keymv.set_value_string(encrypted_key)
! self.keymv.decrypt() # PKop
! decrypted = self.keymv.get_value()
try:
symmetric_key = cryptutil.oaep_decode(decrypted[1:]) # Leave off the initial 0 byte. ### XX check whether it really is 0 and raise bad-encoding error if not. --Zooko 2000-07-29
***************
*** 310,321 ****
full_key = keyutil.makePublicRSAKeyForCommunicating(modval.new(sender_key, HARDCODED_RSA_PUBLIC_EXPONENT))
full_key_id = idlib.make_id(full_key, 'broker')
# the session id for messages sent 'here'
! id_in = _mix_counterparties(full_key_id, self.__my_public_key_id, u.unpack_fstring(SIZE_OF_UNIQS))
# the session id for messages sent 'there'
! id_out = _mix_counterparties(full_key_id, self.__my_public_key_id, u.unpack_fstring(SIZE_OF_UNIQS))
# check that the pk encrypted symmetric key used to send this message is the same was generated properly
strl = u.unpack_fstring(SIZE_OF_UNIQS)
! sr = hashrandom.SHARandom(_mix_counterparties(full_key_id, self.__my_public_key_id, strl))
spaml = sr.get(SIZE_OF_SYMMETRIC_KEYS)
if symmetric_key != spaml:
raise Error, 'improperly generated key'
--- 194,205 ----
full_key = keyutil.makePublicRSAKeyForCommunicating(modval.new(sender_key, HARDCODED_RSA_PUBLIC_EXPONENT))
full_key_id = idlib.make_id(full_key, 'broker')
# the session id for messages sent 'here'
! id_in = _mix_counterparties(full_key_id, self.pkId, u.unpack_fstring(SIZE_OF_UNIQS))
# the session id for messages sent 'there'
! id_out = _mix_counterparties(full_key_id, self.pkId, u.unpack_fstring(SIZE_OF_UNIQS))
# check that the pk encrypted symmetric key used to send this message is the same was generated properly
strl = u.unpack_fstring(SIZE_OF_UNIQS)
! sr = hashrandom.SHARandom(_mix_counterparties(full_key_id, self.pkId, strl))
spaml = sr.get(SIZE_OF_SYMMETRIC_KEYS)
if symmetric_key != spaml:
raise Error, 'improperly generated key'
***************
*** 340,379 ****
if thingie != summary:
raise Error, 'bad signature: %s != %s' % (`thingie`, `summary`)
! self.extres.db_env.nosyncerror_txn_checkpoint(MINS_BETWEEN_DB_CHECKPOINTS)
! trans = self.extres.db_env.txn_begin()
! try:
! # store session info if it's a new one
! if self.extres.counterparty_map.get(full_key_id, txn=trans, flags=db.DB_RMW) is None :
! if self.extres.session_map.get(id_in, txn=trans, flags=db.DB_RMW) is not None :
! raise Error, 'a session with the specified incoming id already exists'
! assert len(symmetric_key) == SIZE_OF_SYMMETRIC_KEYS
! self.extres.session_map.put(id_in, full_key, txn=trans)
! self.extres.counterparty_map.put(full_key_id, dumps([id_in, id_out, symmetric_key, None, full_key], 1), txn=trans)
! else:
! # Hmm.. We already had a session for this counterparty.
! # this means that most likely we both tried to send each other messages to establish a session
! # at the same time or at different times but one message got lost; usually due to the other
! # counterparty being offline at the time or having just switched relay servers.
! #
! # TODO implement this:
! # Accept and store this key and use it in the future. Keep the current key available
! # as well incase they get the session establishing message we sent them and switch to
! # using the session that we setup ourselves.
! # What this would do:
! # prevent the current situation of always sending the header to/from counterparties
! # where initiating session establishing messages have crossed. This is good because
! # full header messages are a bit larger and require two PKops on the receiver if the
! # header is not currently in its in memory parsed headers cache.
! pass
! result = (full_key, symmetric_key)
! self.__cached_headers[hash] = result
! trans.commit()
! trans = None
! return result
! finally:
! if trans is not None:
! trans.abort()
except (modval.Error, tripledescbc.Error, xdrlib.Error, EOFError), le:
debugprint("got error in mesgen.__parse_header(): %s", args=(le,), v=4, vs="debug")
raise Error, le
--- 224,257 ----
if thingie != summary:
raise Error, 'bad signature: %s != %s' % (`thingie`, `summary`)
! # store session info if it's a new one
! if self.counterpartymap.get(full_key_id) is None:
! if self.sessionmap.get(id_in) is not None :
! raise Error, 'a session with the specified incoming id already exists'
! assert len(symmetric_key) == SIZE_OF_SYMMETRIC_KEYS
! self.sessionmap[id_in] = full_key
! self.counterpartymap[full_key_id] = (id_in, id_out, symmetric_key, None, full_key,)
! self._lazy_save(delay=0) # It is important to save to disk ASAP, as I think losing this information might result in a state where we can *never* talk to this counterparty again. (There is no key renegotiation in EGTPv1.) --Zooko 2003-01-30
! else:
! debugprint("Possibly this is an error which prevents me and this other counterparty from ever talking again in the future. counterpartyId: %s\n", args=(full_key_id,))
! # Hmm.. We already had a session for this counterparty.
! # this means that most likely we both tried to send each other messages to establish a session
! # at the same time or at different times but one message got lost; usually due to the other
! # counterparty being offline at the time or having just switched relay servers.
! #
! # TODO implement this:
! # Accept and store this key and use it in the future. Keep the current key available
! # as well incase they get the session establishing message we sent them and switch to
! # using the session that we setup ourselves.
! # What this would do:
! # prevent the current situation of always sending the header to/from counterparties
! # where initiating session establishing messages have crossed. This is good because
! # full header messages are a bit larger and require two PKops on the receiver if the
! # header is not currently in its in memory parsed headers cache.
! pass
! result = (full_key, symmetric_key,)
! self.cachedheaders[hash] = result
! return result
except (modval.Error, tripledescbc.Error, xdrlib.Error, EOFError), le:
debugprint("got error in mesgen.__parse_header(): %s", args=(le,), v=4, vs="debug")
raise Error, le
***************
*** 382,535 ****
"""
@idempotent
"""
! if self.extres.counterparty_map.has_key(idlib.make_id(full_key, 'key')):
return
! self.lock.acquire()
! try:
! return self.__store_key(full_key)
! finally:
! self.lock.release()
!
! def __store_key(self, full_key):
! self.extres.db_env.nosyncerror_txn_checkpoint(MINS_BETWEEN_DB_CHECKPOINTS)
! trans = self.extres.db_env.txn_begin()
! try:
! key_id = sha(full_key).digest()
! if self.extres.counterparty_map.get(key_id, txn=trans, flags=db.DB_RMW) is not None :
! return
! id_in_rep = randsource.get(SIZE_OF_UNIQS)
! id_in = _mix_counterparties(self.__my_public_key_id, key_id, id_in_rep)
! id_out_rep = randsource.get(SIZE_OF_UNIQS)
! id_out = _mix_counterparties(self.__my_public_key_id, key_id, id_out_rep)
! key_seed = randsource.get(SIZE_OF_UNIQS)
! sr = hashrandom.SHARandom(_mix_counterparties(self.__my_public_key_id, key_id, key_seed))
! symmetric_key = sr.get(SIZE_OF_SYMMETRIC_KEYS)
! iv = randsource.get(8)
!
! p = Packer()
! p.pack_fstring(SIZE_OF_UNIQS, key_id)
! x = keyutil.makeRSAPublicKeyMVFromSexpString(full_key)
!
! padded = '\000' + cryptutil.oaep(symmetric_key, len(self.__key.get_modulus()) - 1) # The prepended 0 byte is to make modval happy.
! assert len(padded) == len(self.__key.get_modulus())
!
! x.set_value_string(padded)
! x.encrypt()
! p.pack_string(x.get_value())
! p.pack_fstring(8, iv)
!
! penc = Packer()
! penc.pack_string(self.__key.get_modulus())
! penc.pack_fstring(SIZE_OF_UNIQS, id_out_rep)
! penc.pack_fstring(SIZE_OF_UNIQS, id_in_rep)
! penc.pack_fstring(SIZE_OF_UNIQS, key_seed)
!
! # debugprint("------ ------ ------ ------ hmachish(key=%s, message=%s)\n" % (`symmetric_key`, `penc.get_buffer()`))
! hashie = cryptutil.hmacish(key=symmetric_key, message=penc.get_buffer())
!
! paddedhashie = '\000' + cryptutil.oaep(hashie, len(self.__key.get_modulus()) - 1) # The prepended 0 byte is to make modval happy.
! assert len(paddedhashie) == len(self.__key.get_modulus())
!
! self.__key.set_value_string(paddedhashie)
! self.__key.sign()
! signature = self.__key.get_value()
! penc.pack_fstring(len(signature), signature)
! encrypted = tripledescbc.new(symmetric_key).encrypt(iv, penc.get_buffer())
! p.pack_string(encrypted)
! header = p.get_buffer()
!
! self.extres.counterparty_map.put(key_id, dumps([id_in, id_out, symmetric_key, header, full_key], 1), txn=trans)
!
! self.extres.session_map.put(id_in, full_key, txn=trans)
! trans.commit()
! trans = None
! finally:
! if trans is not None:
! trans.abort()
! def get_connect_info(self, counterparty_id):
! self.lock.acquire()
! try:
! return self.__get_connect_info(counterparty_id)
! finally:
! self.lock.release()
! def __get_connect_info(self, counterparty_id):
"""
Returns either: {'header': ..., 'symmetric_key': ...} {'session_id_out': ..., 'symmetric_key': ...}
Generates new connection info if there is none
! @precondition: `counterparty_id' must be of the right form for an id.: idlib.is_sloppy_id(counterparty_id): "counterparty_id: %s" % hr(counterparty_id)
"""
! assert idlib.is_sloppy_id(counterparty_id), "`counterparty_id' must be of the right form for an id." + " -- " + "counterparty_id: %s" % hr(counterparty_id)
! counterparty_id = idlib.canonicalize(counterparty_id, 'broker')
! self.extres.db_env.nosyncerror_txn_checkpoint(MINS_BETWEEN_DB_CHECKPOINTS)
! infopickle = self.extres.counterparty_map.get(counterparty_id)
! if infopickle is None:
raise NoCounterpartyInfo, 'no counterparty information stored'
# if the session has been verifiably set up, send the session id
# otherwise send the full header
! session_id_out, symmetric_key, header = loads(infopickle)[1:4]
! if header is None :
return {'session_id_out': session_id_out, 'symmetric_key': symmetric_key}
else:
return {'header': header, 'symmetric_key': symmetric_key}
def get_session_info(self, id_in):
- self.lock.acquire()
- try:
- return self.__get_session_info(id_in)
- finally:
- self.lock.release()
-
- def __get_session_info(self, id_in):
"""
Returns (counterparty_pub_key_sexp, symmetric_key, want ack) throws Error
"""
! self.extres.db_env.nosyncerror_txn_checkpoint(MINS_BETWEEN_DB_CHECKPOINTS)
! trans = self.extres.db_env.txn_begin()
! try:
! counterparty_pub_key_sexp = self.extres.session_map.get(id_in, txn=trans)
! if counterparty_pub_key_sexp is None:
! raise UnknownSession(id_in, self.get_id())
! counterparty_id = idlib.make_id(counterparty_pub_key_sexp, 'broker')
! try:
! symmetric_key, header = loads(self.extres.counterparty_map.get(counterparty_id, txn=trans))[2:4]
! except TypeError:
! # well, we did know about the session, but our counterparty database somehow didn't have an entry
! raise UnknownSession(id_in, self.get_id())
! return (counterparty_pub_key_sexp, symmetric_key, header is not None)
! finally:
! if trans is not None:
! trans.abort()
! def invalidate_session(self, bad_session_id_out, counterparty_id):
! self.lock.acquire()
! try:
! return self.__invalidate_session(bad_session_id_out, counterparty_id)
! finally:
! self.lock.release()
!
! def __invalidate_session(self, bad_session_id_out, counterparty_id):
"""
! Removes an outgoing session id from our database if counterparty_id matches the public key id
! associated with this session id. Raises Error if bad_session_id_out is not associated with counterparty_id.
"""
# maps counterparty id to [session_id_in, session_id_out, symmetric_key, header, full pk]
try:
! stored_session_id_out = loads(self.extres.counterparty_map.get(counterparty_id, (None,None,None,None)))[1]
except:
stored_session_id_out = None
! debugprint("__invalidate_session for unverified cid %s, bad_session_id_out %s, stored_session_id_out %s\n", args=(counterparty_id, bad_session_id_out, stored_session_id_out), v=4, vs='mesgen')
if idlib.equal(stored_session_id_out, bad_session_id_out):
! self.extres.counterparty_map.delete(counterparty_id)
else:
! raise Error, "someone asked us to invalidate session_id_out %s, but they claimed that that session was with counterparty %s, but we do not have a that session id as our session id for that counterparty. Not invalidating; we probably connected to broker that is now using a different key from the one we know for the CommStrat" % (`bad_session_id_out`, idlib.to_ascii(counterparty_id))
# TODO this should be its own class of error, if caught it is -reasonable- (though not absolute in
# in the rare case of someone malicious hijacking/inserting data into the TCP stream) to assume
# that any of the messages you just sent down this TCP connection were undecryptable and should
--- 260,371 ----
"""
@idempotent
"""
! if self.counterpartymap.has_key(idlib.make_id(full_key, 'key')):
return
! key_id = sha(full_key).digest()
! if self.counterpartymap.get(key_id) is not None:
! return
! id_in_rep = randsource.get(SIZE_OF_UNIQS)
! id_in = _mix_counterparties(self.pkId, key_id, id_in_rep)
! id_out_rep = randsource.get(SIZE_OF_UNIQS)
! id_out = _mix_counterparties(self.pkId, key_id, id_out_rep)
! key_seed = randsource.get(SIZE_OF_UNIQS)
! sr = hashrandom.SHARandom(_mix_counterparties(self.pkId, key_id, key_seed))
! symmetric_key = sr.get(SIZE_OF_SYMMETRIC_KEYS)
! iv = randsource.get(8)
! p = Packer()
! p.pack_fstring(SIZE_OF_UNIQS, key_id)
! x = keyutil.makeRSAPublicKeyMVFromSexpString(full_key)
!
! padded = '\000' + cryptutil.oaep(symmetric_key, len(self.keymv.get_modulus()) - 1) # The prepended 0 byte is to make modval happy.
! assert len(padded) == len(self.keymv.get_modulus())
!
! x.set_value_string(padded)
! x.encrypt()
! p.pack_string(x.get_value())
! p.pack_fstring(8, iv)
!
! penc = Packer()
! penc.pack_string(self.keymv.get_modulus())
! penc.pack_fstring(SIZE_OF_UNIQS, id_out_rep)
! penc.pack_fstring(SIZE_OF_UNIQS, id_in_rep)
! penc.pack_fstring(SIZE_OF_UNIQS, key_seed)
!
! # debugprint("------ ------ ------ ------ hmachish(key=%s, message=%s)\n" % (`symmetric_key`, `penc.get_buffer()`))
! hashie = cryptutil.hmacish(key=symmetric_key, message=penc.get_buffer())
!
! paddedhashie = '\000' + cryptutil.oaep(hashie, len(self.keymv.get_modulus()) - 1) # The prepended 0 byte is to make modval happy.
! assert len(paddedhashie) == len(self.keymv.get_modulus())
!
! self.keymv.set_value_string(paddedhashie)
! self.keymv.sign()
! signature = self.keymv.get_value()
! penc.pack_fstring(len(signature), signature)
! encrypted = tripledescbc.new(symmetric_key).encrypt(iv, penc.get_buffer())
! p.pack_string(encrypted)
! header = p.get_buffer()
! self.counterpartymap[key_id] = (id_in, id_out, symmetric_key, header, full_key,)
! self.sessionmap[id_in] = full_key
! self._lazy_save(delay=0) # It is important to save to disk ASAP, as I think losing this information might result in a state where we can *never* talk to this counterparty again. (There is no key renegotiation in EGTPv1.) --Zooko 2003-01-30
!
! def get_connect_info(self, counterpartyId):
"""
Returns either: {'header': ..., 'symmetric_key': ...} {'session_id_out': ..., 'symmetric_key': ...}
Generates new connection info if there is none
! @precondition: `counterpartyId' must be of the right form for an id.: idlib.is_sloppy_id(counterpartyId): "counterpartyId: %s" %humanreadable. hr(counterpartyId)
"""
! assert idlib.is_sloppy_id(counterpartyId), "`counterpartyId' must be of the right form for an id." + " -- " + "counterpartyId: %s" %humanreadable. hr(counterpartyId)
! counterpartyId = idlib.canonicalize(counterpartyId, 'broker')
! infotuple = self.counterpartymap.get(counterpartyId)
! if is None:
raise NoCounterpartyInfo, 'no counterparty information stored'
# if the session has been verifiably set up, send the session id
# otherwise send the full header
! session_id_out, symmetric_key, header = infotuple[1:4]
! if header is None:
return {'session_id_out': session_id_out, 'symmetric_key': symmetric_key}
else:
return {'header': header, 'symmetric_key': symmetric_key}
def get_session_info(self, id_in):
"""
Returns (counterparty_pub_key_sexp, symmetric_key, want ack) throws Error
"""
! counterparty_pub_key_sexp = self.sessionmap.get(id_in)
! if counterparty_pub_key_sexp is None:
! raise UnknownSession(id_in, self.get_id())
! counterpartyId = idlib.make_id(counterparty_pub_key_sexp, 'broker')
! try:
! symmetric_key, header = self.counterpartymap[counterpartyId][2:4]
! except TypeError:
! # well, we did know about the session, but our counterparty database somehow didn't have an entry
! raise UnknownSession(id_in, self.get_id())
! return (counterparty_pub_key_sexp, symmetric_key, header is not None)
! def invalidate_session(self, bad_session_id_out, counterpartyId):
"""
! Removes an outgoing session id from our database if counterpartyId matches the public key id
! associated with this session id. Raises Error if bad_session_id_out is not associated with counterpartyId.
"""
# maps counterparty id to [session_id_in, session_id_out, symmetric_key, header, full pk]
try:
! stored_session_id_out = self.counterpartymap.get(counterpartyId, (None,None,None,None))[1]
except:
stored_session_id_out = None
! debugprint("__invalidate_session for unverified cid %s, bad_session_id_out %s, stored_session_id_out %s\n", args=(counterpartyId, bad_session_id_out, stored_session_id_out), v=4, vs='mesgen')
if idlib.equal(stored_session_id_out, bad_session_id_out):
! del self.counterpartymap[counterpartyId]
! self._lazy_save(delay=0) # It is important to save to disk ASAP, as I think losing this information might result in a state where we can *never* talk to this counterparty again. (There is no key renegotiation in EGTPv1.) --Zooko 2003-01-30
else:
! raise Error, "someone asked us to invalidate session_id_out %s, but they claimed that that session was with counterparty %s, but we do not have a that session id as our session id for that counterparty. Not invalidating; we probably connected to broker that is now using a different key from the one we know for the CommStrat" % (`bad_session_id_out`, idlib.to_ascii(counterpartyId))
# TODO this should be its own class of error, if caught it is -reasonable- (though not absolute in
# in the rare case of someone malicious hijacking/inserting data into the TCP stream) to assume
# that any of the messages you just sent down this TCP connection were undecryptable and should
***************
*** 537,550 ****
# "denial of service" from you to the given counterparty that there are -much- easier ways to
# accomplish without sniffing and hijacking connections] -greg 2001-06-04
! def create_MessageMaker(dbparentdir, recoverdb=true):
! return MessageMaker(dbparentdir=dbparentdir, dir=None, recoverdb=recoverdb)
!
!
! def load_MessageMaker(dir, recoverdb=true):
! return MessageMaker(dbparentdir=None, dir=dir, recoverdb=recoverdb)
!
class MessageMaker:
def __init__(self, dbparentdir=None, dir=None, serialized=None, recoverdb=true):
--- 373,385 ----
# "denial of service" from you to the given counterparty that there are -much- easier ways to
# accomplish without sniffing and hijacking connections] -greg 2001-06-04
+ def create_MessageMaker(dbparentdir):
+ return MessageMaker(dbparentdir=dbparentdir, fname=None)
! def load_MessageMaker(fname):
! sk = SessionKeeper(dbparentdir=None, dir=dir, recoverdb=recoverdb)
! xxxx
! return MessageMaker(dbparentdir=None, fname=fname)
class MessageMaker:
def __init__(self, dbparentdir=None, dir=None, serialized=None, recoverdb=true):
***************
*** 567,575 ****
created, named by the mojosixbit encoding of the hash of the key.
@param dir: the directory for this particular key
! @precondition: Exactly one of (dbparentdir, dir) must be not None.: ((dbparentdir is not None) and (dir is None)) or ((dbparentdir is None) and (dir is not None)): "dbparentdir: %s, dir: %s" % (hr(dbparentdir), hr(dir))
"""
! assert ((dbparentdir is not None) and (dir is None)) or ((dbparentdir is None) and (dir is not None)), "precondition: Exactly one of (dbparentdir, dir) must be not None." + " -- " + "dbparentdir: %s, dir: %s" % (hr(dbparentdir), hr(dir))
if dir:
self._session_keeper = SessionKeeper(dbparentdir=None, dir=dir, recoverdb=recoverdb)
--- 402,410 ----
created, named by the mojosixbit encoding of the hash of the key.
@param dir: the directory for this particular key
! @precondition: Exactly one of (dbparentdir, dir) must be not None.: ((dbparentdir is not None) and (dir is None)) or ((dbparentdir is None) and (dir is not None)): "dbparentdir: %s, dir: %s" % humanreadable.(hr(dbparentdir),humanreadable. hr(dir))
"""
! assert ((dbparentdir is not None) and (dir is None)) or ((dbparentdir is None) and (dir is not None)), "precondition: Exactly one of (dbparentdir, dir) must be not None." + " -- " + "dbparentdir: %s, dir: %s" % humanreadable.(hr(dbparentdir),humanreadable. hr(dir))
if dir:
self._session_keeper = SessionKeeper(dbparentdir=None, dir=dir, recoverdb=recoverdb)
***************
*** 593,615 ****
def get_id(self):
return self._session_keeper.get_id()
! def get_counterparty_public_key(self, counterparty_id):
"""
! @precondition: `counterparty_id' must be an id.: idlib.is_sloppy_id(counterparty_id): "id: %s" % hr(id)
"""
! assert idlib.is_sloppy_id(counterparty_id), "precondition: `counterparty_id' must be an id." + " -- " + "id: %s" % hr(id)
! counterparty_id = idlib.canonicalize(counterparty_id, 'broker')
! return self._session_keeper.get_connect_info(counterparty_id)['symmetric_key']
def store_key(self, pub_key_sexp):
"""
! @precondition: `pub_key_sexp' must be a well-formed keyutil.: keyutil.publicKeyForCommunicationSecurityIsWellFormed(pub_key_sexp): "pub_key_sexp: %s" % hr(pub_key_sexp)
@idempotent:
"""
! assert keyutil.publicKeyForCommunicationSecurityIsWellFormed(pub_key_sexp), "`pub_key_sexp' must be a well-formed keyutil." + " -- " + "pub_key_sexp: %s" % hr(pub_key_sexp)
self._session_keeper.store_key(pub_key_sexp)
--- 428,450 ----
def get_id(self):
return self._session_keeper.get_id()
! def get_counterparty_public_key(self, counterpartyId):
"""
! @precondition: `counterpartyId' must be an id.: idlib.is_sloppy_id(counterpartyId): "id: %s" %humanreadable. hr(id)
"""
! assert idlib.is_sloppy_id(counterpartyId), "precondition: `counterpartyId' must be an id." + " -- " + "id: %s" %humanreadable. hr(id)
! counterpartyId = idlib.canonicalize(counterpartyId, 'broker')
! return self._session_keeper.get_connect_info(counterpartyId)['symmetric_key']
def store_key(self, pub_key_sexp):
"""
! @precondition: `pub_key_sexp' must be a well-formed keyutil.: keyutil.publicKeyForCommunicationSecurityIsWellFormed(pub_key_sexp): "pub_key_sexp: %s" %humanreadable. hr(pub_key_sexp)
@idempotent:
"""
! assert keyutil.publicKeyForCommunicationSecurityIsWellFormed(pub_key_sexp), "`pub_key_sexp' must be a well-formed keyutil." + " -- " + "pub_key_sexp: %s" %humanreadable. hr(pub_key_sexp)
self._session_keeper.store_key(pub_key_sexp)
***************
*** 646,655 ****
@raises SessionInvalidated: if the incoming message was an "invalidate session" message \000\000\000\002.
@raises UnknownSession: error if the incoming message did not identify a known session key.
! @precondition: `wired_string' must be a string.: type(wired_string) == types.StringType: "wired_string: %s :: %s" % (hr(wired_string), hr(type(wired_string)))
! @postcondition: `counterparty_pub_key_sexp' is a public key.: keyutil.publicRSAKeyForCommunicationSecurityIsWellFormed(counterparty_pub_key_sexp): "counterparty_pub_key_sexp: %s" % hr(counterparty_pub_key_sexp)
"""
! assert type(wired_string) == types.StringType, "precondition: `wired_string' must be a string." + " -- " + "wired_string: %s :: %s" % (hr(wired_string), hr(type(wired_string)))
session = None
try:
--- 481,490 ----
@raises SessionInvalidated: if the incoming message was an "invalidate session" message \000\000\000\002.
@raises UnknownSession: error if the incoming message did not identify a known session key.
! @precondition: `wired_string' must be a string.: type(wired_string) == types.StringType: "wired_string: %s :: %s" % humanreadable.(hr(wired_string),humanreadable. hr(type(wired_string)))
! @postcondition: `counterparty_pub_key_sexp' is a public key.: keyutil.publicRSAKeyForCommunicationSecurityIsWellFormed(counterparty_pub_key_sexp): "counterparty_pub_key_sexp: %s" %humanreadable. hr(counterparty_pub_key_sexp)
"""
! assert type(wired_string) == types.StringType, "precondition: `wired_string' must be a string." + " -- " + "wired_string: %s :: %s" % humanreadable.(hr(wired_string),humanreadable. hr(type(wired_string)))
session = None
try:
***************
*** 690,709 ****
mac = u.unpack_fstring(SIZE_OF_UNIQS)
u.done()
! counterparty_id = idlib.make_id(counterparty_pub_key_sexp, 'broker')
# debugprint("------ ------ ------ ------ hmachish(key=%s, message=%s)\n" % (`symmetric_key`, `message`))
maccomp = cryptutil.hmacish(key=symmetric_key, message=message)
if mac != maccomp:
raise Error, 'incorrect MAC'
if want_ack:
! self._session_keeper.got_ack(counterparty_id)
return (counterparty_pub_key_sexp, message)
elif mtype == '\000\000\002\002': # a short "message" invalidating an outgoing session id
bad_session_id_out = u.unpack_fstring(SIZE_OF_UNIQS)
! unverified_counterparty_id = u.unpack_fstring(SIZE_OF_UNIQS)
! self._session_keeper.invalidate_session(bad_session_id_out, unverified_counterparty_id)
! raise SessionInvalidated, 'session_id %s with %s invalidated' % (`bad_session_id_out`, idlib.to_ascii(unverified_counterparty_id))
else:
raise Error, 'unsupported message type'
except (modval.Error, tripledescbc.Error, xdrlib.Error, EOFError), le:
--- 525,544 ----
mac = u.unpack_fstring(SIZE_OF_UNIQS)
u.done()
! counterpartyId = idlib.make_id(counterparty_pub_key_sexp, 'broker')
# debugprint("------ ------ ------ ------ hmachish(key=%s, message=%s)\n" % (`symmetric_key`, `message`))
maccomp = cryptutil.hmacish(key=symmetric_key, message=message)
if mac != maccomp:
raise Error, 'incorrect MAC'
if want_ack:
! self._session_keeper.got_ack(counterpartyId)
return (counterparty_pub_key_sexp, message)
elif mtype == '\000\000\002\002': # a short "message" invalidating an outgoing session id
bad_session_id_out = u.unpack_fstring(SIZE_OF_UNIQS)
! unverified_counterpartyId = u.unpack_fstring(SIZE_OF_UNIQS)
! self._session_keeper.invalidate_session(bad_session_id_out, unverified_counterpartyId)
! raise SessionInvalidated, 'session_id %s with %s invalidated' % (`bad_session_id_out`, idlib.to_ascii(unverified_counterpartyId))
else:
raise Error, 'unsupported message type'
except (modval.Error, tripledescbc.Error, xdrlib.Error, EOFError), le:
-------------------------------------------------------
This SF.NET email is sponsored by:
SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
http://www.vasoftware.com
_______________________________________________
mnet-devel mailing list
mnet-devel at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mnet-devel
More information about the Mnet-devel
mailing list