mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-30 01:38:55 +00:00
refactor ed25519 helpers to functional style
eliminates the wrapper classes and uses some more-explicit names throughout (e.g "sk" -> "signing_key")
This commit is contained in:
parent
49b7756a8b
commit
47ccdb0177
@ -11,8 +11,7 @@ from twisted.python.filepath import FilePath
|
||||
from twisted.python.failure import Failure
|
||||
|
||||
import allmydata
|
||||
from allmydata.crypto.ed25519 import SigningKey
|
||||
from allmydata.crypto import rsa
|
||||
from allmydata.crypto import rsa, ed25519
|
||||
from allmydata.storage.server import StorageServer
|
||||
from allmydata import storage_client
|
||||
from allmydata.immutable.upload import Uploader
|
||||
@ -479,19 +478,20 @@ 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():
|
||||
priv_key = SigningKey.generate()
|
||||
return priv_key.encoded_key() + "\n"
|
||||
private_key, _ = ed25519.create_signing_keypair()
|
||||
return ed25519.string_from_signing_key(private_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
|
||||
private_key_str = self.config.get_or_create_private_config("node.privkey", _make_key)
|
||||
private_key, public_key = ed25519.signing_keypair_from_string(private_key_str)
|
||||
public_key_str = ed25519.string_from_verifying_key(public_key)
|
||||
self.config.write_config_file("node.pubkey", public_key_str + "\n")
|
||||
self._node_private_key = private_key
|
||||
self._node_public_key = public_key
|
||||
|
||||
def get_long_nodeid(self):
|
||||
# this matches what IServer.get_longname() says about us elsewhere
|
||||
vk_bytes = self._node_key.public_key().public_bytes()
|
||||
return "v0-"+base32.b2a(vk_bytes)
|
||||
vk_bytes = ed25519.bytes_from_verifying_key(self._node_public_key)
|
||||
return "v0-" + base32.b2a(vk_bytes)
|
||||
|
||||
def get_long_tubid(self):
|
||||
return idlib.nodeid_b2a(self.nodeid)
|
||||
@ -512,7 +512,7 @@ class _Client(node.Node, pollmixin.PollMixin):
|
||||
else:
|
||||
# otherwise, we're free to use the more natural seed of our
|
||||
# pubkey-based serverid
|
||||
vk_bytes = self._node_key.public_key().public_bytes()
|
||||
vk_bytes = ed25519.bytes_from_verifying_key(self._node_public_key)
|
||||
seed = base32.b2a(vk_bytes)
|
||||
self.config.write_config_file("permutation-seed", seed+"\n")
|
||||
return seed.strip()
|
||||
@ -583,7 +583,7 @@ class _Client(node.Node, pollmixin.PollMixin):
|
||||
"permutation-seed-base32": self._init_permutation_seed(ss),
|
||||
}
|
||||
for ic in self.introducer_clients:
|
||||
ic.publish("storage", ann, self._node_key)
|
||||
ic.publish("storage", ann, self._node_private_key)
|
||||
|
||||
def init_client(self):
|
||||
helper_furl = self.config.get_config("client", "helper.furl", None)
|
||||
|
@ -44,95 +44,185 @@ PRIVATE_KEY_PREFIX = 'priv-v0-'
|
||||
PUBLIC_KEY_PREFIX = 'pub-v0-'
|
||||
|
||||
|
||||
class SigningKey:
|
||||
def create_signing_keypair():
|
||||
"""
|
||||
Creates a new ed25519 keypair.
|
||||
|
||||
def __init__(self, priv_key):
|
||||
if not isinstance(priv_key, Ed25519PrivateKey):
|
||||
raise ValueError('priv_key must be an Ed25519PrivateKey')
|
||||
self._priv_key = priv_key
|
||||
:returns: 2-tuple of (private_key, public_key)
|
||||
"""
|
||||
private_key = Ed25519PrivateKey.generate()
|
||||
return private_key, private_key.public_key()
|
||||
|
||||
@classmethod
|
||||
def generate(cls):
|
||||
return cls(Ed25519PrivateKey.generate())
|
||||
|
||||
@classmethod
|
||||
def from_private_bytes(cls, priv_bytes):
|
||||
if not isinstance(priv_bytes, six.binary_type):
|
||||
raise ValueError('priv_bytes must be bytes')
|
||||
return SigningKey(Ed25519PrivateKey.from_private_bytes(priv_bytes))
|
||||
def signing_keypair_from_bytes(private_bytes):
|
||||
"""
|
||||
Creates a ed25519 keypair from serialized bytes
|
||||
|
||||
def private_bytes(self):
|
||||
return self._priv_key.private_bytes(
|
||||
:returns: 2-tuple of (private_key, public_key)
|
||||
"""
|
||||
|
||||
if not isinstance(private_bytes, six.binary_type):
|
||||
raise ValueError('private_bytes must be bytes')
|
||||
private_key = Ed25519PrivateKey.from_private_bytes(private_bytes)
|
||||
return private_key, private_key.public_key()
|
||||
|
||||
|
||||
def bytes_from_signing_key(private_key):
|
||||
"""
|
||||
Turn a private signing key into serialized bytes
|
||||
"""
|
||||
_validate_private_key(private_key)
|
||||
return private_key.private_bytes(
|
||||
Encoding.Raw,
|
||||
PrivateFormat.Raw,
|
||||
NoEncryption(),
|
||||
)
|
||||
|
||||
def public_key(self):
|
||||
return VerifyingKey(self._priv_key.public_key())
|
||||
|
||||
def sign(self, data):
|
||||
def verifying_key_from_signing_key(private_key):
|
||||
"""
|
||||
:returns: the public key associated to the given `private_key`
|
||||
"""
|
||||
_validate_private_key(private_key)
|
||||
return private_key.public_key()
|
||||
|
||||
|
||||
def sign_data(private_key, data):
|
||||
"""
|
||||
Sign the given data using the given private key
|
||||
|
||||
:param private_key: the private part returned from
|
||||
`create_signing_keypair` or from
|
||||
`signing_keypair_from_bytes`
|
||||
|
||||
:param bytes data: the data to sign
|
||||
|
||||
:returns: bytes representing the signature
|
||||
"""
|
||||
|
||||
_validate_private_key(private_key)
|
||||
if not isinstance(data, six.binary_type):
|
||||
raise ValueError('data must be bytes')
|
||||
return self._priv_key.sign(data)
|
||||
|
||||
@classmethod
|
||||
def parse_encoded_key(cls, priv_str):
|
||||
return cls.from_private_bytes(a2b(remove_prefix(priv_str, PRIVATE_KEY_PREFIX)))
|
||||
|
||||
def encoded_key(self):
|
||||
return PRIVATE_KEY_PREFIX + b2a(self.private_bytes())
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, type(self)):
|
||||
return self.private_bytes() == other.private_bytes()
|
||||
else:
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
return private_key.sign(data)
|
||||
|
||||
|
||||
class VerifyingKey:
|
||||
def string_from_signing_key(private_key):
|
||||
"""
|
||||
Encode a private key to a string
|
||||
|
||||
def __init__(self, pub_key):
|
||||
if not isinstance(pub_key, Ed25519PublicKey):
|
||||
raise ValueError('pub_key must be an Ed25519PublicKey')
|
||||
self._pub_key = pub_key
|
||||
:param private_key: the private part returned from
|
||||
`create_signing_keypair` or from
|
||||
`signing_keypair_from_bytes`
|
||||
|
||||
@classmethod
|
||||
def from_public_bytes(cls, pub_bytes):
|
||||
if not isinstance(pub_bytes, six.binary_type):
|
||||
raise ValueError('pub_bytes must be bytes')
|
||||
return cls(Ed25519PublicKey.from_public_bytes(pub_bytes))
|
||||
:returns: string representing this key
|
||||
"""
|
||||
_validate_private_key(private_key)
|
||||
return PRIVATE_KEY_PREFIX + b2a(bytes_from_signing_key(private_key))
|
||||
|
||||
def public_bytes(self):
|
||||
return self._pub_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
|
||||
|
||||
def verify(self, signature, data):
|
||||
if not isinstance(signature, six.binary_type):
|
||||
raise ValueError('signature must be bytes')
|
||||
def signing_keypair_from_string(private_key_str):
|
||||
"""
|
||||
Load a signing keypair from a string
|
||||
|
||||
:returns: a 2-tuple of (private_key, public_key)
|
||||
"""
|
||||
|
||||
return signing_keypair_from_bytes(
|
||||
a2b(remove_prefix(private_key_str, PRIVATE_KEY_PREFIX))
|
||||
)
|
||||
|
||||
|
||||
def verifying_key_from_string(public_key_str):
|
||||
"""
|
||||
Load a verifying key from a string
|
||||
|
||||
:returns: a public_key
|
||||
"""
|
||||
|
||||
|
||||
def verifying_key_from_bytes(public_key_bytes):
|
||||
"""
|
||||
Load a verifying key from bytes
|
||||
|
||||
:returns: a public_key
|
||||
"""
|
||||
if not isinstance(public_key_bytes, six.binary_type):
|
||||
raise ValueError('public_key_bytes must be bytes')
|
||||
return Ed25519PublicKey.from_public_bytes(public_key_bytes)
|
||||
|
||||
|
||||
def bytes_from_verifying_key(public_key):
|
||||
"""
|
||||
Encode a verifying key to bytes.
|
||||
|
||||
:param public_key: the public part of a key returned from
|
||||
`create_signing_keypair` or from
|
||||
`signing_keypair_from_bytes`
|
||||
|
||||
:returns: bytes representing this key
|
||||
"""
|
||||
_validate_public_key(public_key)
|
||||
return public_key.public_bytes(
|
||||
Encoding.Raw,
|
||||
PublicFormat.Raw,
|
||||
)
|
||||
|
||||
|
||||
def verify_signature(public_key, alleged_signature, data):
|
||||
"""
|
||||
:param public_key: a verifying key
|
||||
|
||||
:param bytes alleged_signature: the bytes of the alleged signature
|
||||
|
||||
:param bytes data: the data which was allegedly signed
|
||||
|
||||
:returns: None, or raises an exception if the signature is bad.
|
||||
"""
|
||||
|
||||
if not isinstance(alleged_signature, six.binary_type):
|
||||
raise ValueError('alleged_signature must be bytes')
|
||||
|
||||
if not isinstance(data, six.binary_type):
|
||||
raise ValueError('data must be bytes')
|
||||
|
||||
_validate_public_key(public_key)
|
||||
try:
|
||||
self._pub_key.verify(signature, data)
|
||||
public_key.verify(alleged_signature, data)
|
||||
except InvalidSignature:
|
||||
raise BadSignature
|
||||
|
||||
@classmethod
|
||||
def parse_encoded_key(cls, pub_str):
|
||||
return cls.from_public_bytes(a2b(remove_prefix(pub_str, PUBLIC_KEY_PREFIX)))
|
||||
|
||||
def encoded_key(self):
|
||||
return PUBLIC_KEY_PREFIX + b2a(self.public_bytes())
|
||||
def verifying_key_from_string(public_key_str):
|
||||
return verifying_key_from_bytes(
|
||||
a2b(remove_prefix(public_key_str, PUBLIC_KEY_PREFIX))
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, type(self)):
|
||||
return self.public_bytes() == other.public_bytes()
|
||||
else:
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
def string_from_verifying_key(public_key):
|
||||
"""
|
||||
Encode a public key to a string
|
||||
|
||||
:param public_key: the public part of a keypair
|
||||
|
||||
:returns: string representing this key
|
||||
"""
|
||||
_validate_public_key(public_key)
|
||||
return PUBLIC_KEY_PREFIX + b2a(bytes_from_verifying_key(public_key))
|
||||
|
||||
|
||||
def _validate_public_key(public_key):
|
||||
"""
|
||||
Internal helper. Verify that `public_key` is an appropriate object
|
||||
"""
|
||||
if not isinstance(public_key, Ed25519PublicKey):
|
||||
raise ValueError('public_key must be an Ed25519PublicKey')
|
||||
return None
|
||||
|
||||
|
||||
def _validate_private_key(private_key):
|
||||
"""
|
||||
Internal helper. Verify that `private_key` is an appropriate object
|
||||
"""
|
||||
if not isinstance(private_key, Ed25519PrivateKey):
|
||||
raise ValueError('private_key must be an Ed25519PrivateKey')
|
||||
return None
|
||||
|
@ -1,7 +1,7 @@
|
||||
import re
|
||||
import json
|
||||
from allmydata import crypto
|
||||
from allmydata.crypto.ed25519 import VerifyingKey
|
||||
from allmydata.crypto import ed25519
|
||||
from allmydata.util import base32, rrefutil
|
||||
|
||||
|
||||
@ -15,14 +15,26 @@ def get_tubid_string(furl):
|
||||
return m.group(1).lower()
|
||||
|
||||
|
||||
def sign_to_foolscap(ann, sk):
|
||||
def sign_to_foolscap(announcement, signing_key):
|
||||
"""
|
||||
:param signing_key: a (private) signing key, as returned from
|
||||
e.g. :func:`allmydata.crypto.ed25519.signing_keypair_from_string`
|
||||
|
||||
:returns: 3-tuple of (msg, sig, vk) where msg is a UTF8 JSON
|
||||
serialization of the `announcement`, sig is bytes (a signature of
|
||||
msg) and vk is the verifying key
|
||||
"""
|
||||
# return (bytes, sig-str, pubkey-str). A future HTTP-based serialization
|
||||
# will use JSON({msg:b64(JSON(msg).utf8), sig:v0-b64(sig),
|
||||
# pubkey:v0-b64(pubkey)}) .
|
||||
msg = json.dumps(ann).encode("utf-8")
|
||||
sig = "v0-"+base32.b2a(sk.sign(msg))
|
||||
vk_bytes = sk.public_key().public_bytes()
|
||||
ann_t = (msg, sig, "v0-"+base32.b2a(vk_bytes))
|
||||
msg = json.dumps(announcement).encode("utf-8")
|
||||
sig = "v0-" + base32.b2a(
|
||||
ed25519.sign_data(signing_key, msg)
|
||||
)
|
||||
verifying_key_bytes = ed25519.bytes_from_verifying_key(
|
||||
ed25519.verifying_key_from_signing_key(signing_key)
|
||||
)
|
||||
ann_t = (msg, sig, "v0-" + base32.b2a(verifying_key_bytes))
|
||||
return ann_t
|
||||
|
||||
|
||||
@ -39,9 +51,9 @@ def unsign_from_foolscap(ann_t):
|
||||
if not claimed_key_vs.startswith("v0-"):
|
||||
raise UnknownKeyError("only v0- keys recognized")
|
||||
|
||||
claimed_key = VerifyingKey.parse_encoded_key("pub-" + claimed_key_vs)
|
||||
claimed_key = ed25519.verifying_key_from_string("pub-" + claimed_key_vs)
|
||||
sig_bytes = base32.a2b(crypto.remove_prefix(sig_vs, "v0-"))
|
||||
claimed_key.verify(sig_bytes, msg)
|
||||
ed25519.verify_signature(claimed_key, sig_bytes, msg)
|
||||
key_vs = claimed_key_vs
|
||||
ann = json.loads(msg.decode("utf-8"))
|
||||
return (ann, key_vs)
|
||||
|
@ -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.crypto.ed25519 import SigningKey
|
||||
from allmydata.crypto import ed25519
|
||||
out = options.stdout
|
||||
priv_key = SigningKey.generate()
|
||||
print("private:", priv_key.encoded_key(), file=out)
|
||||
print("public:", priv_key.public_key().encoded_key(), file=out)
|
||||
private_key, public_key = ed25519.create_signing_keypair()
|
||||
print("private:", ed25519.string_from_signing_key(private_key), file=out)
|
||||
print("public:", ed25519.string_from_verifying_key(public_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.crypto.ed25519 import SigningKey
|
||||
from allmydata.crypto import ed25519
|
||||
privkey_vs = options.privkey
|
||||
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)
|
||||
private_key, public_key = ed25519.signing_keypair_from_string(privkey_vs)
|
||||
print("private:", ed25519.string_from_signing_key(private_key), file=out)
|
||||
print("public:", ed25519.string_from_verifying_key(public_key), file=out)
|
||||
return 0
|
||||
|
||||
class AdminCommand(BaseOptions):
|
||||
|
@ -735,16 +735,19 @@ class Admin(unittest.TestCase):
|
||||
self.failUnless(privkey_bits[1].startswith("priv-v0-"), lines[0])
|
||||
self.failUnless(pubkey_bits[1].startswith("pub-v0-"), lines[1])
|
||||
sk_bytes = base32.a2b(crypto.remove_prefix(privkey_bits[1], "priv-v0-"))
|
||||
sk = ed25519.SigningKey.from_private_bytes(sk_bytes)
|
||||
sk, pk = ed25519.signing_keypair_from_bytes(sk_bytes)
|
||||
vk_bytes = base32.a2b(crypto.remove_prefix(pubkey_bits[1], "pub-v0-"))
|
||||
self.failUnlessEqual(sk.public_key().public_bytes(), vk_bytes)
|
||||
self.failUnlessEqual(
|
||||
ed25519.bytes_from_verifying_key(pk),
|
||||
vk_bytes,
|
||||
)
|
||||
d.addCallback(_done)
|
||||
return d
|
||||
|
||||
def test_derive_pubkey(self):
|
||||
priv_key = ed25519.SigningKey.generate()
|
||||
priv_key_str = priv_key.encoded_key()
|
||||
pub_key_str = priv_key.public_key().encoded_key()
|
||||
priv_key, pub_key = ed25519.create_signing_keypair()
|
||||
priv_key_str = ed25519.string_from_signing_key(priv_key)
|
||||
pub_key_str = ed25519.string_from_verifying_key(pub_key)
|
||||
d = run_cli("admin", "derive-pubkey", priv_key_str)
|
||||
def _done(args):
|
||||
(rc, stdout, stderr) = args
|
||||
|
@ -194,15 +194,21 @@ class TestRegression(unittest.TestCase):
|
||||
b'\x86 ier!\xe8\xe5#*\x9d\x8c\x0bI\x02\xd90\x0e7\xbeW\xbf\xa3\xfe\xc1\x1c\xf5+\xe9)'
|
||||
b'\xa3\xde\xc9\xc6s\xc9\x90\xf7x\x08')
|
||||
|
||||
priv_key = ed25519.SigningKey.parse_encoded_key(priv_str)
|
||||
pub_key = ed25519.VerifyingKey.parse_encoded_key(pub_str)
|
||||
private_key, derived_public_key = ed25519.signing_keypair_from_string(priv_str)
|
||||
public_key = ed25519.verifying_key_from_string(pub_str)
|
||||
|
||||
self.failUnlessEqual(priv_key.public_key(), pub_key)
|
||||
self.failUnlessEqual(
|
||||
ed25519.bytes_from_verifying_key(public_key),
|
||||
ed25519.bytes_from_verifying_key(derived_public_key),
|
||||
)
|
||||
|
||||
new_sig = priv_key.sign(test_data)
|
||||
new_sig = ed25519.sign_data(private_key, test_data)
|
||||
self.failUnlessEqual(new_sig, sig)
|
||||
|
||||
pub_key.verify(new_sig, test_data)
|
||||
ed25519.verify_signature(public_key, new_sig, test_data)
|
||||
ed25519.verify_signature(derived_public_key, new_sig, test_data)
|
||||
ed25519.verify_signature(public_key, sig, test_data)
|
||||
ed25519.verify_signature(derived_public_key, sig, test_data)
|
||||
|
||||
def test_decode_rsa_keypair(self):
|
||||
'''
|
||||
@ -216,29 +222,34 @@ class TestRegression(unittest.TestCase):
|
||||
class TestEd25519(unittest.TestCase):
|
||||
|
||||
def test_keys(self):
|
||||
priv_key = ed25519.SigningKey.generate()
|
||||
priv_key_str = priv_key.encoded_key()
|
||||
private_key, public_key = ed25519.create_signing_keypair()
|
||||
private_key_str = ed25519.string_from_signing_key(private_key)
|
||||
|
||||
self.assertIsInstance(priv_key_str, six.string_types)
|
||||
self.assertIsInstance(priv_key.private_bytes(), six.binary_type)
|
||||
self.assertIsInstance(private_key_str, six.string_types)
|
||||
|
||||
priv_key2 = ed25519.SigningKey.parse_encoded_key(priv_key_str)
|
||||
private_key2, public_key2 = ed25519.signing_keypair_from_string(private_key_str)
|
||||
|
||||
self.failUnlessEqual(priv_key, priv_key2)
|
||||
self.failUnlessEqual(
|
||||
ed25519.bytes_from_signing_key(private_key),
|
||||
ed25519.bytes_from_signing_key(private_key2),
|
||||
)
|
||||
self.failUnlessEqual(
|
||||
ed25519.bytes_from_verifying_key(public_key),
|
||||
ed25519.bytes_from_verifying_key(public_key2),
|
||||
)
|
||||
|
||||
pub_key = priv_key.public_key()
|
||||
pub_key2 = priv_key2.public_key()
|
||||
public_key_str = ed25519.string_from_verifying_key(public_key)
|
||||
public_key_bytes = ed25519.bytes_from_verifying_key(public_key)
|
||||
|
||||
self.failUnlessEqual(pub_key, pub_key2)
|
||||
self.assertIsInstance(public_key_str, six.string_types)
|
||||
self.assertIsInstance(public_key_bytes, six.binary_type)
|
||||
|
||||
pub_key_str = pub_key.encoded_key()
|
||||
public_key2 = ed25519.verifying_key_from_string(public_key_str)
|
||||
|
||||
self.assertIsInstance(pub_key_str, six.string_types)
|
||||
self.assertIsInstance(pub_key.public_bytes(), six.binary_type)
|
||||
|
||||
pub_key2 = ed25519.VerifyingKey.parse_encoded_key(pub_key_str)
|
||||
|
||||
self.failUnlessEqual(pub_key, pub_key2)
|
||||
self.failUnlessEqual(
|
||||
ed25519.bytes_from_verifying_key(public_key),
|
||||
ed25519.bytes_from_verifying_key(public_key2),
|
||||
)
|
||||
|
||||
|
||||
class TestRsa(unittest.TestCase):
|
||||
|
@ -15,7 +15,7 @@ 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.ed25519 import SigningKey
|
||||
from allmydata.crypto import ed25519
|
||||
from allmydata.interfaces import InsufficientVersionError
|
||||
from allmydata.introducer.client import IntroducerClient
|
||||
from allmydata.introducer.server import IntroducerService, FurlFileConflictError
|
||||
@ -202,21 +202,21 @@ class Client(AsyncTestCase):
|
||||
furl1a = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:7777/gydnp"
|
||||
furl2 = "pb://ttwwooyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/ttwwoo"
|
||||
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key_str = priv_key.public_key().encoded_key()
|
||||
pubkey_s = crypto.remove_prefix(pub_key_str, "pub-")
|
||||
private_key, public_key = ed25519.create_signing_keypair()
|
||||
public_key_str = ed25519.string_from_verifying_key(public_key)
|
||||
pubkey_s = crypto.remove_prefix(public_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, 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)
|
||||
self.ann1 = make_ann_t(ic1, furl1, private_key, seqnum=10)
|
||||
self.ann1old = make_ann_t(ic1, furl1, private_key, seqnum=9)
|
||||
self.ann1noseqnum = make_ann_t(ic1, furl1, private_key, seqnum=None)
|
||||
self.ann1b = make_ann_t(ic2, furl1, private_key, seqnum=11)
|
||||
self.ann1a = make_ann_t(ic1, furl1a, private_key, seqnum=12)
|
||||
self.ann2 = make_ann_t(ic2, furl2, private_key, seqnum=13)
|
||||
|
||||
ic1.remote_announce_v2([self.ann1]) # queues eventual-send
|
||||
d = fireEventually()
|
||||
@ -300,13 +300,13 @@ class Server(AsyncTestCase):
|
||||
FilePath(self.mktemp()))
|
||||
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:36106/gydnp"
|
||||
|
||||
priv_key = SigningKey.generate()
|
||||
private_key, _ = ed25519.create_signing_keypair()
|
||||
|
||||
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")
|
||||
ann1 = make_ann_t(ic1, furl1, private_key, seqnum=10)
|
||||
ann1_old = make_ann_t(ic1, furl1, private_key, seqnum=9)
|
||||
ann1_new = make_ann_t(ic1, furl1, private_key, seqnum=11)
|
||||
ann1_noseqnum = make_ann_t(ic1, furl1, private_key, seqnum=None)
|
||||
ann1_badseqnum = make_ann_t(ic1, furl1, private_key, seqnum="not an int")
|
||||
|
||||
i.remote_publish_v2(ann1, None)
|
||||
all = i.get_announcements()
|
||||
@ -397,7 +397,7 @@ class Queue(SystemTestMixin, AsyncTestCase):
|
||||
u"nickname", "version", "oldest", {}, fakeseq,
|
||||
FilePath(self.mktemp()))
|
||||
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
||||
priv_key = SigningKey.generate()
|
||||
private_key, _ = ed25519.create_signing_keypair()
|
||||
|
||||
d = introducer.disownServiceParent()
|
||||
|
||||
@ -405,7 +405,7 @@ class Queue(SystemTestMixin, AsyncTestCase):
|
||||
# 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), priv_key)
|
||||
c.publish("storage", make_ann(furl1), private_key)
|
||||
|
||||
introducer.setServiceParent(self.parent) # restart the server
|
||||
# now wait for the messages to be delivered
|
||||
@ -486,16 +486,16 @@ class SystemTest(SystemTestMixin, AsyncTestCase):
|
||||
expected_announcements[i] += 1 # all expect a 'storage' announcement
|
||||
|
||||
node_furl = tub.registerReference(Referenceable())
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key_str = priv_key.public_key().encoded_key()
|
||||
privkeys[i] = priv_key
|
||||
pubkeys[i] = pub_key_str
|
||||
private_key, public_key = ed25519.create_signing_keypair()
|
||||
public_key_str = ed25519.string_from_verifying_key(public_key)
|
||||
privkeys[i] = private_key
|
||||
pubkeys[i] = public_key_str
|
||||
|
||||
if i < NUM_STORAGE:
|
||||
# sign all announcements
|
||||
c.publish("storage", make_ann(node_furl), priv_key)
|
||||
assert pub_key_str.startswith("pub-")
|
||||
printable_serverids[i] = pub_key_str[len("pub-"):]
|
||||
c.publish("storage", make_ann(node_furl), private_key)
|
||||
assert public_key_str.startswith("pub-")
|
||||
printable_serverids[i] = public_key_str[len("pub-"):]
|
||||
publishing_clients.append(c)
|
||||
else:
|
||||
# the last one does not publish anything
|
||||
@ -504,7 +504,7 @@ 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), priv_key)
|
||||
c.publish("boring", make_ann(boring_furl), private_key)
|
||||
|
||||
c.setServiceParent(self.parent)
|
||||
clients.append(c)
|
||||
@ -760,17 +760,16 @@ class Announcements(AsyncTestCase):
|
||||
fakeseq, FilePath(self.mktemp()))
|
||||
furl1 = "pb://62ubehyunnyhzs7r6vdonnm2hpi52w6y@127.0.0.1:0/swissnum"
|
||||
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key = priv_key.public_key()
|
||||
pks = crypto.remove_prefix(pub_key.encoded_key(), "pub-")
|
||||
private_key, public_key = ed25519.create_signing_keypair()
|
||||
public_key_str = crypto.remove_prefix(ed25519.string_from_verifying_key(public_key), "pub-")
|
||||
|
||||
ann_t0 = make_ann_t(client_v2, furl1, priv_key, 10)
|
||||
ann_t0 = make_ann_t(client_v2, furl1, private_key, 10)
|
||||
canary0 = Referenceable()
|
||||
introducer.remote_publish_v2(ann_t0, canary0)
|
||||
a = introducer.get_announcements()
|
||||
self.failUnlessEqual(len(a), 1)
|
||||
self.assertThat(a[0].canary, Is(canary0))
|
||||
self.failUnlessEqual(a[0].index, ("storage", pks))
|
||||
self.failUnlessEqual(a[0].index, ("storage", public_key_str))
|
||||
self.failUnlessEqual(a[0].announcement["app-versions"], app_versions)
|
||||
self.failUnlessEqual(a[0].nickname, u"nick-v2")
|
||||
self.failUnlessEqual(a[0].service_name, "storage")
|
||||
@ -800,11 +799,10 @@ class Announcements(AsyncTestCase):
|
||||
|
||||
c = yield create_client(basedir)
|
||||
ic = c.introducer_clients[0]
|
||||
priv_key = SigningKey.generate()
|
||||
pub_key = priv_key.public_key()
|
||||
pub_key_str = crypto.remove_prefix(pub_key.encoded_key(), "pub-")
|
||||
private_key, public_key = ed25519.create_signing_keypair()
|
||||
public_key_str = crypto.remove_prefix(ed25519.string_from_verifying_key(public_key), "pub-")
|
||||
furl1 = "pb://onug64tu@127.0.0.1:123/short" # base32("short")
|
||||
ann_t = make_ann_t(ic, furl1, priv_key, 1)
|
||||
ann_t = make_ann_t(ic, furl1, private_key, 1)
|
||||
|
||||
ic.got_announcements([ann_t])
|
||||
yield flushEventualQueue()
|
||||
@ -812,7 +810,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'], pub_key_str)
|
||||
self.failUnlessEqual(announcements[0]['key_s'], public_key_str)
|
||||
ann = announcements[0]["ann"]
|
||||
self.failUnlessEqual(ann["anonymous-storage-FURL"], furl1)
|
||||
self.failUnlessEqual(ann["seqnum"], 1)
|
||||
@ -820,29 +818,28 @@ 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, priv_key, 2)
|
||||
ann_t2 = make_ann_t(ic, furl2, private_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'], pub_key_str)
|
||||
self.failUnlessEqual(announcements[0]['key_s'], public_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
|
||||
priv_key2 = SigningKey.generate()
|
||||
pub_key2 = priv_key2.public_key()
|
||||
pub_key_str2 = crypto.remove_prefix(pub_key2.encoded_key(), "pub-")
|
||||
private_key2, public_key2 = ed25519.create_signing_keypair()
|
||||
public_key_str2 = crypto.remove_prefix(ed25519.string_from_verifying_key(public_key2), "pub-")
|
||||
furl3 = "pb://onug64tu@127.0.0.1:456/short"
|
||||
ann_t3 = make_ann_t(ic, furl3, priv_key2, 1)
|
||||
ann_t3 = make_ann_t(ic, furl3, private_key2, 1)
|
||||
ic.got_announcements([ann_t3])
|
||||
yield flushEventualQueue()
|
||||
|
||||
announcements = self._load_cache(cache_filepath)
|
||||
self.failUnlessEqual(len(announcements), 2)
|
||||
self.failUnlessEqual(set([pub_key_str, pub_key_str2]),
|
||||
self.failUnlessEqual(set([public_key_str, public_key_str2]),
|
||||
set([a["key_s"] for a in announcements]))
|
||||
self.failUnlessEqual(set([furl2, furl3]),
|
||||
set([a["ann"]["anonymous-storage-FURL"]
|
||||
@ -860,17 +857,17 @@ class Announcements(AsyncTestCase):
|
||||
ic2._load_announcements() # normally happens when connection fails
|
||||
yield flushEventualQueue()
|
||||
|
||||
self.failUnless(pub_key_str in announcements)
|
||||
self.failUnlessEqual(announcements[pub_key_str]["anonymous-storage-FURL"],
|
||||
self.failUnless(public_key_str in announcements)
|
||||
self.failUnlessEqual(announcements[public_key_str]["anonymous-storage-FURL"],
|
||||
furl2)
|
||||
self.failUnlessEqual(announcements[pub_key_str2]["anonymous-storage-FURL"],
|
||||
self.failUnlessEqual(announcements[public_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([pub_key_str, pub_key_str2]))
|
||||
frozenset([public_key_str, public_key_str2]))
|
||||
|
||||
class ClientSeqnums(AsyncBrokenTestCase):
|
||||
|
||||
@ -899,7 +896,7 @@ class ClientSeqnums(AsyncBrokenTestCase):
|
||||
f.close()
|
||||
return int(seqnum)
|
||||
|
||||
ic.publish("sA", {"key": "value1"}, c._node_key)
|
||||
ic.publish("sA", {"key": "value1"}, c._node_private_key)
|
||||
self.failUnlessEqual(read_seqnum(), 1)
|
||||
self.failUnless("sA" in outbound)
|
||||
self.failUnlessEqual(outbound["sA"]["seqnum"], 1)
|
||||
@ -911,7 +908,7 @@ class ClientSeqnums(AsyncBrokenTestCase):
|
||||
|
||||
# publishing a second service causes both services to be
|
||||
# re-published, with the next higher sequence number
|
||||
ic.publish("sB", {"key": "value2"}, c._node_key)
|
||||
ic.publish("sB", {"key": "value2"}, c._node_private_key)
|
||||
self.failUnlessEqual(read_seqnum(), 2)
|
||||
self.failUnless("sB" in outbound)
|
||||
self.failUnlessEqual(outbound["sB"]["seqnum"], 2)
|
||||
@ -986,8 +983,9 @@ class Signatures(SyncTestCase):
|
||||
|
||||
def test_sign(self):
|
||||
ann = {"key1": "value1"}
|
||||
priv_key = SigningKey.generate()
|
||||
ann_t = sign_to_foolscap(ann, priv_key)
|
||||
private_key, public_key = ed25519.create_signing_keypair()
|
||||
public_key_str = ed25519.string_from_verifying_key(public_key)
|
||||
ann_t = sign_to_foolscap(ann, private_key)
|
||||
(msg, sig, key) = ann_t
|
||||
self.failUnlessEqual(type(msg), type("".encode("utf-8"))) # bytes
|
||||
self.failUnlessEqual(json.loads(msg.decode("utf-8")), ann)
|
||||
@ -995,7 +993,7 @@ class Signatures(SyncTestCase):
|
||||
self.failUnless(key.startswith("v0-"))
|
||||
(ann2,key2) = unsign_from_foolscap(ann_t)
|
||||
self.failUnlessEqual(ann2, ann)
|
||||
self.failUnlessEqual("pub-" + key2, priv_key.public_key().encoded_key())
|
||||
self.failUnlessEqual("pub-" + key2, public_key_str)
|
||||
|
||||
# not signed
|
||||
self.failUnlessRaises(UnknownKeyError,
|
||||
|
Loading…
Reference in New Issue
Block a user