mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-30 01:38:55 +00:00
update code/test to use new ed25512 module
This commit is contained in:
parent
3a5a0fb572
commit
9e31bfe2f4
@ -12,14 +12,14 @@ from twisted.python.failure import Failure
|
||||
from pycryptopp.publickey import rsa
|
||||
|
||||
import allmydata
|
||||
from allmydata.crypto.ed25519 import SigningKey
|
||||
from allmydata.storage.server import StorageServer
|
||||
from allmydata import storage_client
|
||||
from allmydata.immutable.upload import Uploader
|
||||
from allmydata.immutable.offloaded import Helper
|
||||
from allmydata.control import ControlServer
|
||||
from allmydata.introducer.client import IntroducerClient
|
||||
from allmydata.util import (hashutil, base32, pollmixin, log, keyutil, idlib,
|
||||
yamlutil)
|
||||
from allmydata.util import (hashutil, base32, pollmixin, log, idlib, yamlutil)
|
||||
from allmydata.util.encodingutil import (get_filesystem_encoding,
|
||||
from_utf8_or_none)
|
||||
from allmydata.util.abbreviate import parse_abbreviated_size
|
||||
@ -480,12 +480,14 @@ class _Client(node.Node, pollmixin.PollMixin):
|
||||
# we only create the key once. On all subsequent runs, we re-use the
|
||||
# existing key
|
||||
def _make_key():
|
||||
sk_vs,vk_vs = keyutil.make_keypair()
|
||||
return sk_vs+"\n"
|
||||
sk_vs = self.config.get_or_create_private_config("node.privkey", _make_key)
|
||||
sk,vk_vs = keyutil.parse_privkey(sk_vs.strip())
|
||||
self.config.write_config_file("node.pubkey", vk_vs+"\n")
|
||||
self._node_key = sk
|
||||
priv_key = SigningKey.generate()
|
||||
return priv_key.encoded_key() + "\n"
|
||||
|
||||
priv_key_str = self.config.get_or_create_private_config("node.privkey", _make_key)
|
||||
priv_key = SigningKey.parse_encoded_key(priv_key_str)
|
||||
pub_key_str = priv_key.public_key().encoded_key()
|
||||
self.config.write_config_file("node.pubkey", pub_key_str + "\n")
|
||||
self._node_key = priv_key
|
||||
|
||||
def get_long_nodeid(self):
|
||||
# this matches what IServer.get_longname() says about us elsewhere
|
||||
|
@ -1 +1,8 @@
|
||||
class BadPrefixError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def remove_prefix(s_bytes, prefix):
|
||||
if not s_bytes.startswith(prefix):
|
||||
raise BadPrefixError("did not see expected '%s' prefix" % (prefix,))
|
||||
return s_bytes[len(prefix):]
|
||||
|
@ -28,22 +28,13 @@ from cryptography.exceptions import InvalidSignature
|
||||
BadSignatureError = InvalidSignature
|
||||
del InvalidSignature
|
||||
|
||||
from allmydata.crypto import remove_prefix
|
||||
from allmydata.util.base32 import a2b, b2a
|
||||
|
||||
_PRIV_PREFIX = 'priv-v0-'
|
||||
_PUB_PREFIX = 'pub-v0-'
|
||||
|
||||
|
||||
class BadPrefixError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _remove_prefix(s_bytes, prefix):
|
||||
if not s_bytes.startswith(prefix):
|
||||
raise BadPrefixError("did not see expected '%s' prefix" % (prefix,))
|
||||
return s_bytes[len(prefix):]
|
||||
|
||||
|
||||
class SigningKey:
|
||||
|
||||
def __init__(self, priv_key):
|
||||
@ -79,11 +70,11 @@ class SigningKey:
|
||||
@classmethod
|
||||
def parse_encoded_key(cls, priv_str):
|
||||
global _PRIV_PREFIX
|
||||
return cls.from_private_bytes(a2b(_remove_prefix(priv_str, _PRIV_PREFIX)))
|
||||
return cls.from_private_bytes(a2b(remove_prefix(priv_str, _PRIV_PREFIX)))
|
||||
|
||||
def encoded_key(self):
|
||||
global _PRIV_PREFIX
|
||||
return _PRIV_PREFIX + a2b(self.private_bytes())
|
||||
return _PRIV_PREFIX + b2a(self.private_bytes())
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, type(self)):
|
||||
@ -123,11 +114,11 @@ class VerifyingKey:
|
||||
@classmethod
|
||||
def parse_encoded_key(cls, pub_str):
|
||||
global _PUB_PREFIX
|
||||
return cls.from_public_bytes(a2b(_remove_prefix(pub_str, _PUB_PREFIX)))
|
||||
return cls.from_public_bytes(a2b(remove_prefix(pub_str, _PUB_PREFIX)))
|
||||
|
||||
def encoded_key(self):
|
||||
global _PUB_PREFIX
|
||||
return _PUB_PREFIX + a2b(self.public_bytes())
|
||||
return _PUB_PREFIX + b2a(self.public_bytes())
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, type(self)):
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import time
|
||||
from zope.interface import implementer
|
||||
from twisted.application import service
|
||||
@ -10,7 +9,7 @@ from allmydata.introducer.common import sign_to_foolscap, unsign_from_foolscap,\
|
||||
get_tubid_string_from_ann
|
||||
from allmydata.util import log, yamlutil, connection_status
|
||||
from allmydata.util.rrefutil import add_version_to_remote_reference
|
||||
from allmydata.util.keyutil import BadSignatureError
|
||||
from allmydata.crypto.ed25519 import BadSignatureError
|
||||
from allmydata.util.assertutil import precondition
|
||||
|
||||
class InvalidCacheError(Exception):
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
import re
|
||||
import json
|
||||
from allmydata.util import keyutil, base32, rrefutil
|
||||
from allmydata import crypto
|
||||
from allmydata.crypto.ed25519 import VerifyingKey
|
||||
from allmydata.util import base32, rrefutil
|
||||
|
||||
|
||||
def get_tubid_string_from_ann(ann):
|
||||
return get_tubid_string(str(ann.get("anonymous-storage-FURL")
|
||||
@ -23,9 +25,11 @@ def sign_to_foolscap(ann, sk):
|
||||
ann_t = (msg, sig, "v0-"+base32.b2a(vk_bytes))
|
||||
return ann_t
|
||||
|
||||
|
||||
class UnknownKeyError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def unsign_from_foolscap(ann_t):
|
||||
(msg, sig_vs, claimed_key_vs) = ann_t
|
||||
if not sig_vs or not claimed_key_vs:
|
||||
@ -34,8 +38,9 @@ def unsign_from_foolscap(ann_t):
|
||||
raise UnknownKeyError("only v0- signatures recognized")
|
||||
if not claimed_key_vs.startswith("v0-"):
|
||||
raise UnknownKeyError("only v0- keys recognized")
|
||||
claimed_key = keyutil.parse_pubkey("pub-"+claimed_key_vs)
|
||||
sig_bytes = base32.a2b(keyutil.remove_prefix(sig_vs, "v0-"))
|
||||
|
||||
claimed_key = VerifyingKey.parse_encoded_key("pub-" + claimed_key_vs)
|
||||
sig_bytes = base32.a2b(crypto.remove_prefix(sig_vs, "v0-"))
|
||||
claimed_key.verify(sig_bytes, msg)
|
||||
key_vs = claimed_key_vs
|
||||
ann = json.loads(msg.decode("utf-8"))
|
||||
|
@ -14,11 +14,11 @@ Generate a public/private keypair, dumped to stdout as two lines of ASCII..
|
||||
return t
|
||||
|
||||
def print_keypair(options):
|
||||
from allmydata.util.keyutil import make_keypair
|
||||
from allmydata.crypto.ed25519 import SigningKey
|
||||
out = options.stdout
|
||||
privkey_vs, pubkey_vs = make_keypair()
|
||||
print("private:", privkey_vs, file=out)
|
||||
print("public:", pubkey_vs, file=out)
|
||||
priv_key = SigningKey.generate()
|
||||
print("private:", priv_key.encoded_key(), file=out)
|
||||
print("public:", priv_key.public_key().encoded_key(), file=out)
|
||||
|
||||
class DerivePubkeyOptions(BaseOptions):
|
||||
def parseArgs(self, privkey):
|
||||
@ -38,11 +38,11 @@ generate-keypair, derive the public key and print it to stdout.
|
||||
|
||||
def derive_pubkey(options):
|
||||
out = options.stdout
|
||||
from allmydata.util import keyutil
|
||||
from allmydata.crypto.ed25519 import SigningKey
|
||||
privkey_vs = options.privkey
|
||||
sk, pubkey_vs = keyutil.parse_privkey(privkey_vs)
|
||||
print("private:", privkey_vs, file=out)
|
||||
print("public:", pubkey_vs, file=out)
|
||||
priv_key = SigningKey.parse_encoded_key(privkey_vs)
|
||||
print("private:", priv_key.encoded_key(), file=out)
|
||||
print("public:", priv_key.public_key().encoded_key(), file=out)
|
||||
return 0
|
||||
|
||||
class AdminCommand(BaseOptions):
|
||||
|
@ -10,8 +10,9 @@ from twisted.internet import task
|
||||
from twisted.python.filepath import FilePath
|
||||
|
||||
import allmydata
|
||||
from allmydata import crypto
|
||||
from allmydata.crypto import ed25519
|
||||
from allmydata.util import fileutil, hashutil, base32, keyutil
|
||||
from allmydata.util import fileutil, hashutil, base32
|
||||
from allmydata.util.namespace import Namespace
|
||||
from allmydata import uri
|
||||
from allmydata.immutable import upload
|
||||
@ -34,10 +35,10 @@ from allmydata.scripts.common import DEFAULT_ALIAS, get_aliases, get_alias, \
|
||||
DefaultAliasMarker
|
||||
|
||||
from allmydata.scripts import cli, debug, runner
|
||||
from ..common_util import (ReallyEqualMixin, skip_if_cannot_represent_filename,
|
||||
run_cli)
|
||||
from ..no_network import GridTestMixin
|
||||
from .common import CLITestMixin, parse_options
|
||||
from allmydata.test.common_util import (ReallyEqualMixin, skip_if_cannot_represent_filename,
|
||||
run_cli)
|
||||
from allmydata.test.no_network import GridTestMixin
|
||||
from allmydata.test.cli.common import CLITestMixin, parse_options
|
||||
from twisted.python import usage
|
||||
|
||||
from allmydata.util.encodingutil import listdir_unicode, get_io_encoding
|
||||
@ -733,16 +734,18 @@ class Admin(unittest.TestCase):
|
||||
self.failUnlessEqual(pubkey_bits[0], vk_header, lines[1])
|
||||
self.failUnless(privkey_bits[1].startswith("priv-v0-"), lines[0])
|
||||
self.failUnless(pubkey_bits[1].startswith("pub-v0-"), lines[1])
|
||||
sk_bytes = base32.a2b(keyutil.remove_prefix(privkey_bits[1], "priv-v0-"))
|
||||
sk_bytes = base32.a2b(crypto.remove_prefix(privkey_bits[1], "priv-v0-"))
|
||||
sk = ed25519.SigningKey.from_private_bytes(sk_bytes)
|
||||
vk_bytes = base32.a2b(keyutil.remove_prefix(pubkey_bits[1], "pub-v0-"))
|
||||
vk_bytes = base32.a2b(crypto.remove_prefix(pubkey_bits[1], "pub-v0-"))
|
||||
self.failUnlessEqual(sk.public_key().public_bytes(), vk_bytes)
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
def test_derive_pubkey(self):
|
||||
priv1,pub1 = keyutil.make_keypair()
|
||||
d = run_cli("admin", "derive-pubkey", priv1)
|
||||
priv_key = ed25519.SigningKey.generate()
|
||||
priv_key_str = priv_key.encoded_key()
|
||||
pub_key_str = priv_key.public_key().encoded_key()
|
||||
d = run_cli("admin", "derive-pubkey", priv_key_str)
|
||||
def _done(args):
|
||||
(rc, stdout, stderr) = args
|
||||
lines = stdout.split("\n")
|
||||
@ -752,8 +755,8 @@ class Admin(unittest.TestCase):
|
||||
vk_header = "public: pub-v0-"
|
||||
self.failUnless(privkey_line.startswith(sk_header), privkey_line)
|
||||
self.failUnless(pubkey_line.startswith(vk_header), pubkey_line)
|
||||
pub2 = pubkey_line[len(vk_header):]
|
||||
self.failUnlessEqual("pub-v0-"+pub2, pub1)
|
||||
pub_key_str2 = pubkey_line[len(vk_header):]
|
||||
self.failUnlessEqual("pub-v0-" + pub_key_str2, pub_key_str)
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
|
@ -174,3 +174,31 @@ class TestRegression(unittest.TestCase):
|
||||
self.failUnlessEqual(new_sig, sig)
|
||||
|
||||
pub_key.verify(new_sig, test_data)
|
||||
|
||||
|
||||
class TestEd25519(unittest.TestCase):
|
||||
|
||||
def test_keys(self):
|
||||
priv_key = SigningKey.generate()
|
||||
priv_key_str = priv_key.encoded_key()
|
||||
|
||||
self.assertIsInstance(priv_key_str, six.string_types)
|
||||
self.assertIsInstance(priv_key.private_bytes(), six.binary_type)
|
||||
|
||||
priv_key2 = SigningKey.parse_encoded_key(priv_key_str)
|
||||
|
||||
self.failUnlessEqual(priv_key, priv_key2)
|
||||
|
||||
pub_key = priv_key.public_key()
|
||||
pub_key2 = priv_key2.public_key()
|
||||
|
||||
self.failUnlessEqual(pub_key, pub_key2)
|
||||
|
||||
pub_key_str = pub_key.encoded_key()
|
||||
|
||||
self.assertIsInstance(pub_key_str, six.string_types)
|
||||
self.assertIsInstance(pub_key.public_bytes(), six.binary_type)
|
||||
|
||||
pub_key2 = VerifyingKey.parse_encoded_key(pub_key_str)
|
||||
|
||||
self.failUnlessEqual(pub_key, pub_key2)
|
||||
|
@ -14,6 +14,9 @@ from twisted.python.filepath import FilePath
|
||||
|
||||
from foolscap.api import Tub, Referenceable, fireEventually, flushEventualQueue
|
||||
from twisted.application import service
|
||||
from allmydata import crypto
|
||||
from allmydata.crypto import ed25519
|
||||
from allmydata.crypto.ed25519 import SigningKey
|
||||
from allmydata.interfaces import InsufficientVersionError
|
||||
from allmydata.introducer.client import IntroducerClient
|
||||
from allmydata.introducer.server import IntroducerService, FurlFileConflictError
|
||||
@ -31,12 +34,12 @@ from allmydata.client import (
|
||||
create_client,
|
||||
create_introducer_clients,
|
||||
)
|
||||
from allmydata.util import pollmixin, keyutil, idlib, fileutil, yamlutil
|
||||
from allmydata.util import pollmixin, idlib, fileutil, yamlutil
|
||||
from allmydata.util.iputil import (
|
||||
listenOnUnused,
|
||||
)
|
||||
import allmydata.test.common_util as testutil
|
||||
from .common import (
|
||||
from allmydata.test.common import (
|
||||
SyncTestCase,
|
||||
AsyncTestCase,
|
||||
AsyncBrokenTestCase,
|
||||
@ -200,21 +203,21 @@ class Client(AsyncTestCase):
|
||||
furl1a = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:7777/gydnp"
|
||||
furl2 = "pb://ttwwooyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/ttwwoo"
|
||||
|
||||
privkey_s, pubkey_vs = keyutil.make_keypair()
|
||||
privkey, _ignored = keyutil.parse_privkey(privkey_s)
|
||||
pubkey_s = keyutil.remove_prefix(pubkey_vs, "pub-")
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key_str = priv_key.public_key().encoded_key()
|
||||
pubkey_s = crypto.remove_prefix(pub_key_str, "pub-")
|
||||
|
||||
# ann1: ic1, furl1
|
||||
# ann1a: ic1, furl1a (same SturdyRef, different connection hints)
|
||||
# ann1b: ic2, furl1
|
||||
# ann2: ic2, furl2
|
||||
|
||||
self.ann1 = make_ann_t(ic1, furl1, privkey, seqnum=10)
|
||||
self.ann1old = make_ann_t(ic1, furl1, privkey, seqnum=9)
|
||||
self.ann1noseqnum = make_ann_t(ic1, furl1, privkey, seqnum=None)
|
||||
self.ann1b = make_ann_t(ic2, furl1, privkey, seqnum=11)
|
||||
self.ann1a = make_ann_t(ic1, furl1a, privkey, seqnum=12)
|
||||
self.ann2 = make_ann_t(ic2, furl2, privkey, seqnum=13)
|
||||
self.ann1 = make_ann_t(ic1, furl1, priv_key, seqnum=10)
|
||||
self.ann1old = make_ann_t(ic1, furl1, priv_key, seqnum=9)
|
||||
self.ann1noseqnum = make_ann_t(ic1, furl1, priv_key, seqnum=None)
|
||||
self.ann1b = make_ann_t(ic2, furl1, priv_key, seqnum=11)
|
||||
self.ann1a = make_ann_t(ic1, furl1a, priv_key, seqnum=12)
|
||||
self.ann2 = make_ann_t(ic2, furl2, priv_key, seqnum=13)
|
||||
|
||||
ic1.remote_announce_v2([self.ann1]) # queues eventual-send
|
||||
d = fireEventually()
|
||||
@ -298,14 +301,13 @@ class Server(AsyncTestCase):
|
||||
FilePath(self.mktemp()))
|
||||
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/gydnp"
|
||||
|
||||
privkey_s, _ = keyutil.make_keypair()
|
||||
privkey, _ = keyutil.parse_privkey(privkey_s)
|
||||
priv_key = SigningKey.generate()
|
||||
|
||||
ann1 = make_ann_t(ic1, furl1, privkey, seqnum=10)
|
||||
ann1_old = make_ann_t(ic1, furl1, privkey, seqnum=9)
|
||||
ann1_new = make_ann_t(ic1, furl1, privkey, seqnum=11)
|
||||
ann1_noseqnum = make_ann_t(ic1, furl1, privkey, seqnum=None)
|
||||
ann1_badseqnum = make_ann_t(ic1, furl1, privkey, seqnum="not an int")
|
||||
ann1 = make_ann_t(ic1, furl1, priv_key, seqnum=10)
|
||||
ann1_old = make_ann_t(ic1, furl1, priv_key, seqnum=9)
|
||||
ann1_new = make_ann_t(ic1, furl1, priv_key, seqnum=11)
|
||||
ann1_noseqnum = make_ann_t(ic1, furl1, priv_key, seqnum=None)
|
||||
ann1_badseqnum = make_ann_t(ic1, furl1, priv_key, seqnum="not an int")
|
||||
|
||||
i.remote_publish_v2(ann1, None)
|
||||
all = i.get_announcements()
|
||||
@ -396,22 +398,24 @@ class Queue(SystemTestMixin, AsyncTestCase):
|
||||
u"nickname", "version", "oldest", {}, fakeseq,
|
||||
FilePath(self.mktemp()))
|
||||
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
||||
sk_s, vk_s = keyutil.make_keypair()
|
||||
sk, _ignored = keyutil.parse_privkey(sk_s)
|
||||
priv_key = SigningKey.generate()
|
||||
|
||||
d = introducer.disownServiceParent()
|
||||
|
||||
def _offline(ign):
|
||||
# now that the introducer server is offline, create a client and
|
||||
# publish some messages
|
||||
c.setServiceParent(self.parent) # this starts the reconnector
|
||||
c.publish("storage", make_ann(furl1), sk)
|
||||
c.publish("storage", make_ann(furl1), priv_key)
|
||||
|
||||
introducer.setServiceParent(self.parent) # restart the server
|
||||
# now wait for the messages to be delivered
|
||||
def _got_announcement():
|
||||
return bool(introducer.get_announcements())
|
||||
return self.poll(_got_announcement)
|
||||
|
||||
d.addCallback(_offline)
|
||||
|
||||
def _done(ign):
|
||||
v = introducer.get_announcements()[0]
|
||||
furl = v.announcement["anonymous-storage-FURL"]
|
||||
@ -427,6 +431,7 @@ class Queue(SystemTestMixin, AsyncTestCase):
|
||||
return False
|
||||
return True
|
||||
return self.poll(_idle)
|
||||
|
||||
d.addCallback(_wait_until_idle)
|
||||
return d
|
||||
|
||||
@ -482,16 +487,16 @@ class SystemTest(SystemTestMixin, AsyncTestCase):
|
||||
expected_announcements[i] += 1 # all expect a 'storage' announcement
|
||||
|
||||
node_furl = tub.registerReference(Referenceable())
|
||||
privkey_s, pubkey_s = keyutil.make_keypair()
|
||||
privkey, _ignored = keyutil.parse_privkey(privkey_s)
|
||||
privkeys[i] = privkey
|
||||
pubkeys[i] = pubkey_s
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key_str = priv_key.public_key().encoded_key()
|
||||
privkeys[i] = priv_key
|
||||
pubkeys[i] = pub_key_str
|
||||
|
||||
if i < NUM_STORAGE:
|
||||
# sign all announcements
|
||||
c.publish("storage", make_ann(node_furl), privkey)
|
||||
assert pubkey_s.startswith("pub-")
|
||||
printable_serverids[i] = pubkey_s[len("pub-"):]
|
||||
c.publish("storage", make_ann(node_furl), priv_key)
|
||||
assert pub_key_str.startswith("pub-")
|
||||
printable_serverids[i] = pub_key_str[len("pub-"):]
|
||||
publishing_clients.append(c)
|
||||
else:
|
||||
# the last one does not publish anything
|
||||
@ -500,13 +505,12 @@ class SystemTest(SystemTestMixin, AsyncTestCase):
|
||||
if i == 2:
|
||||
# also publish something that nobody cares about
|
||||
boring_furl = tub.registerReference(Referenceable())
|
||||
c.publish("boring", make_ann(boring_furl), privkey)
|
||||
c.publish("boring", make_ann(boring_furl), priv_key)
|
||||
|
||||
c.setServiceParent(self.parent)
|
||||
clients.append(c)
|
||||
tubs[c] = tub
|
||||
|
||||
|
||||
def _wait_for_connected(ign):
|
||||
def _connected():
|
||||
for c in clients:
|
||||
@ -746,6 +750,7 @@ class ClientInfo(AsyncTestCase):
|
||||
self.failUnlessEqual(s0.nickname, NICKNAME % u"v2")
|
||||
self.failUnlessEqual(s0.version, "my_version")
|
||||
|
||||
|
||||
class Announcements(AsyncTestCase):
|
||||
def test_client_v2_signed(self):
|
||||
introducer = IntroducerService()
|
||||
@ -755,10 +760,12 @@ class Announcements(AsyncTestCase):
|
||||
"my_version", "oldest", app_versions,
|
||||
fakeseq, FilePath(self.mktemp()))
|
||||
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
||||
sk_s, vk_s = keyutil.make_keypair()
|
||||
sk, _ignored = keyutil.parse_privkey(sk_s)
|
||||
pks = keyutil.remove_prefix(vk_s, "pub-")
|
||||
ann_t0 = make_ann_t(client_v2, furl1, sk, 10)
|
||||
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key = priv_key.public_key()
|
||||
pks = crypto.remove_prefix(pub_key.encoded_key(), "pub-")
|
||||
|
||||
ann_t0 = make_ann_t(client_v2, furl1, priv_key, 10)
|
||||
canary0 = Referenceable()
|
||||
introducer.remote_publish_v2(ann_t0, canary0)
|
||||
a = introducer.get_announcements()
|
||||
@ -786,20 +793,19 @@ class Announcements(AsyncTestCase):
|
||||
# during startup (although the announcement will wait in a queue
|
||||
# until the introducer connection is established). To avoid getting
|
||||
# confused by this, disable storage.
|
||||
f = open(os.path.join(basedir, "tahoe.cfg"), "w")
|
||||
f.write("[client]\n")
|
||||
f.write("introducer.furl = nope\n")
|
||||
f.write("[storage]\n")
|
||||
f.write("enabled = false\n")
|
||||
f.close()
|
||||
with open(os.path.join(basedir, "tahoe.cfg"), "w") as f:
|
||||
f.write("[client]\n")
|
||||
f.write("introducer.furl = nope\n")
|
||||
f.write("[storage]\n")
|
||||
f.write("enabled = false\n")
|
||||
|
||||
c = yield create_client(basedir)
|
||||
ic = c.introducer_clients[0]
|
||||
sk_s, vk_s = keyutil.make_keypair()
|
||||
sk, _ignored = keyutil.parse_privkey(sk_s)
|
||||
pub1 = keyutil.remove_prefix(vk_s, "pub-")
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key = priv_key.public_key()
|
||||
pub_key_str = crypto.remove_prefix(pub_key.encoded_key(), "pub-")
|
||||
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
||||
ann_t = make_ann_t(ic, furl1, sk, 1)
|
||||
ann_t = make_ann_t(ic, furl1, priv_key, 1)
|
||||
|
||||
ic.got_announcements([ann_t])
|
||||
yield flushEventualQueue()
|
||||
@ -807,7 +813,7 @@ class Announcements(AsyncTestCase):
|
||||
# check the cache for the announcement
|
||||
announcements = self._load_cache(cache_filepath)
|
||||
self.failUnlessEqual(len(announcements), 1)
|
||||
self.failUnlessEqual(announcements[0]['key_s'], pub1)
|
||||
self.failUnlessEqual(announcements[0]['key_s'], pub_key_str)
|
||||
ann = announcements[0]["ann"]
|
||||
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
||||
self.failUnlessEqual(ann["seqnum"], 1)
|
||||
@ -815,29 +821,29 @@ class Announcements(AsyncTestCase):
|
||||
# a new announcement that replaces the first should replace the
|
||||
# cached entry, not duplicate it
|
||||
furl2 = furl1 + "er"
|
||||
ann_t2 = make_ann_t(ic, furl2, sk, 2)
|
||||
ann_t2 = make_ann_t(ic, furl2, priv_key, 2)
|
||||
ic.got_announcements([ann_t2])
|
||||
yield flushEventualQueue()
|
||||
announcements = self._load_cache(cache_filepath)
|
||||
self.failUnlessEqual(len(announcements), 1)
|
||||
self.failUnlessEqual(announcements[0]['key_s'], pub1)
|
||||
self.failUnlessEqual(announcements[0]['key_s'], pub_key_str)
|
||||
ann = announcements[0]["ann"]
|
||||
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl2)
|
||||
self.failUnlessEqual(ann["seqnum"], 2)
|
||||
|
||||
# but a third announcement with a different key should add to the
|
||||
# cache
|
||||
sk_s2, vk_s2 = keyutil.make_keypair()
|
||||
sk2, _ignored = keyutil.parse_privkey(sk_s2)
|
||||
pub2 = keyutil.remove_prefix(vk_s2, "pub-")
|
||||
priv_key2 = SigningKey.generate()
|
||||
pub_key2 = priv_key2.public_key()
|
||||
pub_key_str2 = crypto.remove_prefix(pub_key2.encoded_key(), "pub-")
|
||||
furl3 = "pb://onug64tu@127.0.0.1:456/short"
|
||||
ann_t3 = make_ann_t(ic, furl3, sk2, 1)
|
||||
ann_t3 = make_ann_t(ic, furl3, priv_key2, 1)
|
||||
ic.got_announcements([ann_t3])
|
||||
yield flushEventualQueue()
|
||||
|
||||
announcements = self._load_cache(cache_filepath)
|
||||
self.failUnlessEqual(len(announcements), 2)
|
||||
self.failUnlessEqual(set([pub1, pub2]),
|
||||
self.failUnlessEqual(set([pub_key_str, pub_key_str2]),
|
||||
set([a["key_s"] for a in announcements]))
|
||||
self.failUnlessEqual(set([furl2, furl3]),
|
||||
set([a["ann"]["anonymous-storage-FURL"]
|
||||
@ -855,17 +861,17 @@ class Announcements(AsyncTestCase):
|
||||
ic2._load_announcements() # normally happens when connection fails
|
||||
yield flushEventualQueue()
|
||||
|
||||
self.failUnless(pub1 in announcements)
|
||||
self.failUnlessEqual(announcements[pub1]["anonymous-storage-FURL"],
|
||||
self.failUnless(pub_key_str in announcements)
|
||||
self.failUnlessEqual(announcements[pub_key_str]["anonymous-storage-FURL"],
|
||||
furl2)
|
||||
self.failUnlessEqual(announcements[pub2]["anonymous-storage-FURL"],
|
||||
self.failUnlessEqual(announcements[pub_key_str2]["anonymous-storage-FURL"],
|
||||
furl3)
|
||||
|
||||
c2 = yield create_client(basedir)
|
||||
c2.introducer_clients[0]._load_announcements()
|
||||
yield flushEventualQueue()
|
||||
self.assertEqual(c2.storage_broker.get_all_serverids(),
|
||||
frozenset([pub1, pub2]))
|
||||
frozenset([pub_key_str, pub_key_str2]))
|
||||
|
||||
class ClientSeqnums(AsyncBrokenTestCase):
|
||||
|
||||
@ -978,11 +984,11 @@ class DecodeFurl(SyncTestCase):
|
||||
self.failUnlessEqual(nodeid, "\x9fM\xf2\x19\xcckU0\xbf\x03\r\x10\x99\xfb&\x9b-\xc7A\x1d")
|
||||
|
||||
class Signatures(SyncTestCase):
|
||||
|
||||
def test_sign(self):
|
||||
ann = {"key1": "value1"}
|
||||
sk_s,vk_s = keyutil.make_keypair()
|
||||
sk,ignored = keyutil.parse_privkey(sk_s)
|
||||
ann_t = sign_to_foolscap(ann, sk)
|
||||
priv_key = SigningKey.generate()
|
||||
ann_t = sign_to_foolscap(ann, priv_key)
|
||||
(msg, sig, key) = ann_t
|
||||
self.failUnlessEqual(type(msg), type("".encode("utf-8"))) # bytes
|
||||
self.failUnlessEqual(json.loads(msg.decode("utf-8")), ann)
|
||||
@ -990,7 +996,7 @@ class Signatures(SyncTestCase):
|
||||
self.failUnless(key.startswith("v0-"))
|
||||
(ann2,key2) = unsign_from_foolscap(ann_t)
|
||||
self.failUnlessEqual(ann2, ann)
|
||||
self.failUnlessEqual("pub-"+key2, vk_s)
|
||||
self.failUnlessEqual("pub-" + key2, priv_key.public_key().encoded_key())
|
||||
|
||||
# not signed
|
||||
self.failUnlessRaises(UnknownKeyError,
|
||||
@ -1000,14 +1006,14 @@ class Signatures(SyncTestCase):
|
||||
# bad signature
|
||||
bad_ann = {"key1": "value2"}
|
||||
bad_msg = json.dumps(bad_ann).encode("utf-8")
|
||||
self.failUnlessRaises(keyutil.BadSignatureError,
|
||||
unsign_from_foolscap, (bad_msg,sig,key))
|
||||
self.failUnlessRaises(ed25519.BadSignatureError,
|
||||
unsign_from_foolscap, (bad_msg, sig, key))
|
||||
|
||||
# unrecognized signatures
|
||||
self.failUnlessRaises(UnknownKeyError,
|
||||
unsign_from_foolscap, (bad_msg,"v999-sig",key))
|
||||
unsign_from_foolscap, (bad_msg, "v999-sig", key))
|
||||
self.failUnlessRaises(UnknownKeyError,
|
||||
unsign_from_foolscap, (bad_msg,sig,"v999-key"))
|
||||
unsign_from_foolscap, (bad_msg, sig, "v999-key"))
|
||||
|
||||
|
||||
# add tests of StorageFarmBroker: if it receives duplicate announcements, it
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import time, os.path, platform, stat, re, json, struct, shutil
|
||||
|
||||
from twisted.trial import unittest
|
||||
|
@ -1,4 +1,5 @@
|
||||
# from the Python Standard Library
|
||||
import six
|
||||
import string
|
||||
|
||||
from allmydata.util.assertutil import precondition
|
||||
@ -179,13 +180,13 @@ def init_s5():
|
||||
s5 = init_s5()
|
||||
|
||||
def could_be_base32_encoded(s, s8=s8, tr=string.translate, identitytranstable=identitytranstable, chars=chars):
|
||||
precondition(isinstance(s, str), s)
|
||||
precondition(isinstance(s, six.binary_type), s)
|
||||
if s == '':
|
||||
return True
|
||||
return s8[len(s)%8][ord(s[-1])] and not tr(s, identitytranstable, chars)
|
||||
|
||||
def could_be_base32_encoded_l(s, lengthinbits, s5=s5, tr=string.translate, identitytranstable=identitytranstable, chars=chars):
|
||||
precondition(isinstance(s, str), s)
|
||||
precondition(isinstance(s, six.binary_type), s)
|
||||
if s == '':
|
||||
return True
|
||||
assert lengthinbits%5 < len(s5), lengthinbits
|
||||
@ -201,7 +202,7 @@ def a2b(cs):
|
||||
@param cs the base-32 encoded data (a string)
|
||||
"""
|
||||
precondition(could_be_base32_encoded(cs), "cs is required to be possibly base32 encoded data.", cs=cs)
|
||||
precondition(isinstance(cs, str), cs)
|
||||
precondition(isinstance(cs, six.binary_type), cs)
|
||||
|
||||
return a2b_l(cs, num_octets_that_encode_to_this_many_quintets(len(cs))*8)
|
||||
|
||||
@ -226,7 +227,7 @@ def a2b_l(cs, lengthinbits):
|
||||
@return the data encoded in cs
|
||||
"""
|
||||
precondition(could_be_base32_encoded_l(cs, lengthinbits), "cs is required to be possibly base32 encoded data.", cs=cs, lengthinbits=lengthinbits)
|
||||
precondition(isinstance(cs, str), cs)
|
||||
precondition(isinstance(cs, six.binary_type), cs)
|
||||
if cs == '':
|
||||
return ''
|
||||
|
||||
|
@ -9,11 +9,13 @@ from allmydata.web.common import (
|
||||
from allmydata.util.abbreviate import abbreviate_space
|
||||
from allmydata.util import time_format, idlib
|
||||
|
||||
|
||||
def remove_prefix(s, prefix):
|
||||
if not s.startswith(prefix):
|
||||
return None
|
||||
return s[len(prefix):]
|
||||
|
||||
|
||||
class StorageStatus(MultiFormatPage):
|
||||
docFactory = getxmlfile("storage_status.xhtml")
|
||||
# the default 'data' argument is the StorageServer instance
|
||||
|
Loading…
Reference in New Issue
Block a user