From 59632c68128c0f4b72c7d805f7b3cf192e7926b5 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Mon, 5 Nov 2007 21:51:08 -0700
Subject: [PATCH] mutable: use proper enable/renew/cancel secrets

---
 src/allmydata/dirnode2.py          |  4 ++--
 src/allmydata/mutable.py           | 33 +++++++++++++++++++++++-------
 src/allmydata/test/test_mutable.py | 12 ++++++-----
 src/allmydata/util/hashutil.py     |  7 +++++++
 4 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/src/allmydata/dirnode2.py b/src/allmydata/dirnode2.py
index 21eeeddc..5cdec394 100644
--- a/src/allmydata/dirnode2.py
+++ b/src/allmydata/dirnode2.py
@@ -73,7 +73,7 @@ class NewDirectoryNode:
     def _encrypt_rwcap(self, rwcap):
         assert isinstance(rwcap, str)
         IV = os.urandom(16)
-        key = hashutil.mutable_rwcap_key_hash(IV, self._node.writekey)
+        key = hashutil.mutable_rwcap_key_hash(IV, self._node.get_writekey())
         counterstart = "\x00"*16
         cryptor = AES.new(key=key, mode=AES.MODE_CTR, counterstart=counterstart)
         crypttext = cryptor.encrypt(rwcap)
@@ -85,7 +85,7 @@ class NewDirectoryNode:
         IV = encwrcap[:16]
         crypttext = encwrcap[16:-32]
         mac = encwrcap[-32:]
-        key = hashutil.mutable_rwcap_key_hash(IV, self._node.writekey)
+        key = hashutil.mutable_rwcap_key_hash(IV, self._node.get_writekey())
         if mac != hashutil.hmac(key, IV+crypttext):
             raise IntegrityCheckError("HMAC does not match, crypttext is corrupted")
         counterstart = "\x00"*16
diff --git a/src/allmydata/mutable.py b/src/allmydata/mutable.py
index a77e3e98..4c62dc03 100644
--- a/src/allmydata/mutable.py
+++ b/src/allmydata/mutable.py
@@ -41,6 +41,9 @@ class MutableFileNode:
         # wants to get our contents, we'll pull from shares and fill those
         # in.
         self._uri = IMutableFileURI(myuri)
+        self._writekey = self._uri.writekey
+        self._readkey = self._uri.readkey
+        self._storage_index = self._uri.storage_index
         return self
 
     def create(self, initial_contents):
@@ -58,6 +61,19 @@ class MutableFileNode:
         return d
 
 
+    def get_write_enabler(self, nodeid):
+        return hashutil.ssk_write_enabler_hash(self._writekey, nodeid)
+    def get_renewal_secret(self, nodeid):
+        crs = self._client.get_renewal_secret()
+        frs = hashutil.file_renewal_secret_hash(crs, self._storage_index)
+        return hashutil.bucket_renewal_secret_hash(frs, nodeid)
+    def get_cancel_secret(self, nodeid):
+        ccs = self._client.get_cancel_secret()
+        fcs = hashutil.file_cancel_secret_hash(ccs, self._storage_index)
+        return hashutil.bucket_cancel_secret_hash(fcs, nodeid)
+    def get_writekey(self):
+        return self._writekey
+
     def get_uri(self):
         return self._uri.to_string()
 
@@ -482,8 +498,15 @@ class Publish(ShareFormattingMixin):
         dl = []
         # ok, send the messages!
         self._surprised = False
+
         for peerid, tw_vectors in peer_messages.items():
-            d = self._do_testreadwrite(peerid, peer_storage_servers,
+
+            write_enabler = self._node.get_write_enabler(peerid)
+            renew_secret = self._node.get_renewal_secret(peerid)
+            cancel_secret = self._node.get_cancel_secret(peerid)
+            secrets = (write_enabler, renew_secret, cancel_secret)
+
+            d = self._do_testreadwrite(peerid, peer_storage_servers, secrets,
                                        tw_vectors, read_vector)
             d.addCallback(self._got_write_answer,
                           peerid, expected_old_shares[peerid])
@@ -493,18 +516,14 @@ class Publish(ShareFormattingMixin):
         d.addCallback(lambda res: self._surprised)
         return d
 
-    def _do_testreadwrite(self, peerid, peer_storage_servers,
+    def _do_testreadwrite(self, peerid, peer_storage_servers, secrets,
                           tw_vectors, read_vector):
         conn = peer_storage_servers[peerid]
         storage_index = self._node._uri.storage_index
-        # TOTALLY BOGUS renew/cancel secrets
-        write_enabler = hashutil.tagged_hash("WEFOO", storage_index)
-        renew_secret = hashutil.tagged_hash("renewFOO", storage_index)
-        cancel_secret = hashutil.tagged_hash("cancelFOO", storage_index)
 
         d = conn.callRemote("slot_testv_and_readv_and_writev",
                             storage_index,
-                            (write_enabler, renew_secret, cancel_secret),
+                            secrets,
                             tw_vectors,
                             read_vector)
         return d
diff --git a/src/allmydata/test/test_mutable.py b/src/allmydata/test/test_mutable.py
index 9acc1e68..56f4285e 100644
--- a/src/allmydata/test/test_mutable.py
+++ b/src/allmydata/test/test_mutable.py
@@ -46,10 +46,6 @@ class FakeFilenode(mutable.MutableFileNode):
     counter = itertools.count(1)
     all_contents = {}
 
-    def init_from_uri(self, myuri):
-        self._uri = myuri
-        self.writekey = myuri.writekey
-        return self
     def create(self, initial_contents):
         count = self.counter.next()
         self.init_from_uri(uri.WriteableSSKFileURI("key%d" % count,
@@ -72,7 +68,8 @@ class FakePublish(mutable.Publish):
         shares = self._peers[peerid]
         return defer.succeed(shares)
 
-    def _do_testreadwrite(self, conn, peerid, tw_vectors, read_vector):
+    def _do_testreadwrite(self, peerid, peer_storage_servers, secrets,
+                          tw_vectors, read_vector):
         # always-pass: parrot the test vectors back to them.
         readv = {}
         for shnum, (testv, datav, new_length) in tw_vectors.items():
@@ -94,6 +91,11 @@ class MyClient:
         self._peerids = [tagged_hash("peerid", "%d" % i)
                          for i in range(self._num_peers)]
 
+    def get_renewal_secret(self):
+        return "I hereby permit you to renew my files"
+    def get_cancel_secret(self):
+        return "I hereby permit you to cancel my leases"
+
     def create_empty_dirnode(self):
         n = FakeNewDirectoryNode(self)
         d = n.create()
diff --git a/src/allmydata/util/hashutil.py b/src/allmydata/util/hashutil.py
index bf2747a1..8424d755 100644
--- a/src/allmydata/util/hashutil.py
+++ b/src/allmydata/util/hashutil.py
@@ -120,6 +120,13 @@ def mutable_rwcap_key_hash(iv, writekey):
     return tagged_pair_hash("allmydata_mutable_rwcap_key_v1", iv, writekey)
 def ssk_writekey_hash(privkey):
     return tagged_hash("allmydata_mutable_writekey_v1", privkey)
+def ssk_write_enabler_master_hash(writekey):
+    return tagged_hash("allmydata_mutable_write_enabler_master_v1", writekey)
+def ssk_write_enabler_hash(writekey, nodeid):
+    assert len(nodeid) == 32 # binary!
+    wem = ssk_write_enabler_master_hash(writekey)
+    return tagged_pair_hash("allmydata_mutable_write_enabler_v1", wem, nodeid)
+
 def ssk_pubkey_fingerprint_hash(pubkey):
     return tagged_hash("allmydata_mutable_pubkey_v1", pubkey)
 
-- 
2.45.2