Re: Creating proxies with different hmac_key

Giovanni Porcari <[email protected]> Wed, 30 Oct 2013 00:15:37 +0100
Newsgroups gmane.comp.python.pyro
Message-ID <[email protected]>
Il giorno 29/ott/2013, alle ore 20:39, Irmen de Jong <[email protected]> ha scritto:

> On 29-10-2013 11:11, Giovanni Porcari wrote:
>> Hi all
>> 
>> i am using pyro4 and I should  connect to different pyro4 daemons in different servers
>> that uses different hmac_keys.
>> 
>> So I would like to write :
>> 
>> proxy_to_foo = Pyro4.Proxy(uri_foo,hmac_key='myfookey')
>> proxy_to_bar = Pyro4.Proxy(uri_bar,hmac_key='mybarkey')
>> 
>> But unfortunately i can only use Pyro4.config.HMAC_KEY= 'mykey'
>> 
>> Any suggestion ?
>> 
> 
> This is not possible at this time.
> 
> It is on the TODO list though. With an equally likely alternative to remove the HMAC in
> its current form altogether. Would you miss it if it is gone?
> 
> Irmen
> 



Hi Irmen

I think that HMAC feature offers us a bit more secure connections
so i really prefer to have it.
In last hours I had a very quick look to the code and i tried to
add this feature (maybe in an ugly way...).

It seems working to me but of course I am eager to know your opinion.

Thank you for your work :)

G.

------------------------------------------------------------------------------
Android is increasing in popularity, but the open development platform that
developers love is also attractive to malware creators. Download this white
paper to learn more about secure code signing practices that can help keep
Android apps secure.
http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk

_______________________________________________
Pyro-core mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/pyro-core
patch.diff (application/octet-stream, 7.2 KB)
diff --git a/src/Pyro4/core.py b/src/Pyro4/core.py
index 2087a05..824f054 100644
--- a/src/Pyro4/core.py
+++ b/src/Pyro4/core.py
@@ -176,9 +176,9 @@ class Proxy(object):
     .. automethod:: _pyroBatch
     .. automethod:: _pyroAsync
     """
-    __pyroAttributes=frozenset(["__getnewargs__", "__getinitargs__", "_pyroConnection", "_pyroUri", "_pyroOneway", "_pyroTimeout", "_pyroSeq"])
+    __pyroAttributes=frozenset(["__getnewargs__", "__getinitargs__", "_pyroHmacKey", "_pyroConnection", "_pyroUri", "_pyroOneway", "_pyroTimeout", "_pyroSeq"])
 
-    def __init__(self, uri):
+    def __init__(self, uri, hmac_key=None):
         """
         .. autoattribute:: _pyroOneway
         .. autoattribute:: _pyroTimeout
@@ -189,12 +189,14 @@ class Proxy(object):
         elif not isinstance(uri, URI):
             raise TypeError("expected Pyro URI")
         self._pyroUri=uri
+        self._pyroHmacKey=hmac_key
         self._pyroConnection=None
         self._pyroOneway=set()
         self._pyroSeq=0    # message sequence number
         self.__pyroTimeout=Pyro4.config.COMMTIMEOUT
         self.__pyroLock=threadutil.Lock()
         self.__pyroConnLock=threadutil.Lock()
+        
         util.get_serializer(Pyro4.config.SERIALIZER)  # assert that the configured serializer is available
         if os.name=="java" and Pyro4.config.SERIALIZER=="marshal":
             import warnings
@@ -296,14 +298,14 @@ class Proxy(object):
             self._pyroSeq=(self._pyroSeq+1)&0xffff
             if Pyro4.config.LOGWIRE:
                 log.debug("proxy wiredata sending: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" % (Pyro4.message.MSG_INVOKE, flags, serializer.serializer_id, self._pyroSeq, data))
-            msg = Message(Pyro4.message.MSG_INVOKE, data, serializer.serializer_id, flags, self._pyroSeq)
+            msg = Message(Pyro4.message.MSG_INVOKE, data, serializer.serializer_id, flags, self._pyroSeq, hmac_key= self._pyroHmacKey)
             try:
                 self._pyroConnection.send(msg.to_bytes())
                 del msg  # invite GC to collect the object, don't wait for out-of-scope
                 if flags & Pyro4.message.FLAGS_ONEWAY:
                     return None    # oneway call, no response data
                 else:
-                    msg = Message.recv(self._pyroConnection, [Pyro4.message.MSG_RESULT])
+                    msg = Message.recv(self._pyroConnection, [Pyro4.message.MSG_RESULT],hmac_key=self._pyroHmacKey)
                     if Pyro4.config.LOGWIRE:
                         log.debug("proxy wiredata received: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" % (msg.type, msg.flags, msg.serializer_id, msg.seq, msg.data) )
                     self.__pyroCheckSequence(msg.seq)
@@ -355,7 +357,7 @@ class Proxy(object):
                     sock=socketutil.createSocket(connect=connect_location, reuseaddr=Pyro4.config.SOCK_REUSE, timeout=self.__pyroTimeout)
                     conn=socketutil.SocketConnection(sock, uri.object)
                     # Do handshake. For now, no need to send anything. (message type CONNECT is not yet used)
-                    msg = Message.recv(conn, None)
+                    msg = Message.recv(conn, None,hmac_key=self._pyroHmacKey)
                     # any trailing data (dataLen>0) is an error message, if any
                 except Exception:
                     x=sys.exc_info()[1]
diff --git a/src/Pyro4/message.py b/src/Pyro4/message.py
index 5f45f4b..c77f46f 100755
--- a/src/Pyro4/message.py
+++ b/src/Pyro4/message.py
@@ -78,12 +78,12 @@ class Message(object):
     An 'HMAC' annotation chunk contains the hmac digest of the message data bytes and
     all of the annotation chunk data bytes (except those of the HMAC chunk itself).
     """
-    __slots__ = ["type", "flags", "seq", "data", "data_size", "serializer_id", "annotations", "annotations_size"]
+    __slots__ = ["type", "flags", "seq", "data", "data_size", "serializer_id", "annotations", "annotations_size","hmac_key"]
     header_format = '!4sHHHHiHHHH'
     header_size = struct.calcsize(header_format)
     checksum_magic = 0x34E9
 
-    def __init__(self, msgType, databytes, serializer_id, flags, seq, annotations=None):
+    def __init__(self, msgType, databytes, serializer_id, flags, seq, annotations=None,hmac_key=None):
         self.type = msgType
         self.flags = flags
         self.seq = seq
@@ -91,8 +91,9 @@ class Message(object):
         self.data_size = len(self.data)
         self.serializer_id = serializer_id
         self.annotations = annotations or {}
-        if Pyro4.config.HMAC_KEY:
-            self.annotations["HMAC"] = self.hmac()
+        self.hmac_key=hmac_key or Pyro4.config.HMAC_KEY
+        if self.hmac_key:
+            self.annotations["HMAC"] = self.hmac(hmac_key=self.hmac_key)
         self.annotations_size = sum([6+len(v) for v in self.annotations.values()])
         if 0 < Pyro4.config.MAX_MESSAGE_SIZE < (self.data_size + self.annotations_size):
             raise errors.ProtocolError("max message size exceeded (%d where max=%d)" % (self.data_size+self.annotations_size, Pyro4.config.MAX_MESSAGE_SIZE))
@@ -150,13 +151,14 @@ class Message(object):
         return msg
 
     @classmethod
-    def recv(cls, connection, requiredMsgTypes=None):
+    def recv(cls, connection, requiredMsgTypes=None, hmac_key=None):
         """
         Receives a pyro message from a given connection.
         Accepts the given message types (None=any, or pass a sequence).
         Also reads annotation chunks and the actual payload data.
         Validates a HMAC chunk if present.
         """
+        hmac_key=hmac_key or Pyro4.config.HMAC_KEY
         msg = cls.from_header(connection.recv(cls.header_size))
         if 0 < Pyro4.config.MAX_MESSAGE_SIZE < (msg.data_size+msg.annotations_size):
             errorMsg = "max message size exceeded (%d where max=%d)" % (msg.data_size+msg.annotations_size, Pyro4.config.MAX_MESSAGE_SIZE)
@@ -180,20 +182,22 @@ class Message(object):
                 i += 6+length
         # read data
         msg.data = connection.recv(msg.data_size)
-        if "HMAC" in msg.annotations and Pyro4.config.HMAC_KEY:
-            if msg.annotations["HMAC"] != msg.hmac():
+        if "HMAC" in msg.annotations and hmac_key:
+            if msg.annotations["HMAC"] != msg.hmac(hmac_key=hmac_key):
                 raise errors.SecurityError("message hmac mismatch")
-        elif ("HMAC" in msg.annotations) != bool(Pyro4.config.HMAC_KEY):
+        elif ("HMAC" in msg.annotations) != bool(hmac_key):
             # Message contains hmac and local HMAC_KEY not set, or vice versa. This is not allowed.
             err = "hmac key config not symmetric"
             log.warning(err)
             raise errors.SecurityError(err)
         return msg
 
-    def hmac(self):
+    def hmac(self,hmac_key=None):
         """returns the hmac of the data and the annotation chunk values (except HMAC chunk itself)"""
-        mac = hmac.new(Pyro4.config.HMAC_KEY, self.data, digestmod=hashlib.sha1)
+        hmac_key=hmac_key or Pyro4.config.HMAC_KEY
+        mac = hmac.new(hmac_key, self.data, digestmod=hashlib.sha1)
         for k, v in self.annotations.items():
             if k != "HMAC":
                 mac.update(v)
         return mac.digest()
+