Add keypair to NodeMaker.create_mutable_file

Previously `NodeMaker` always took responsibility for generating a keypair to
use.  Now the caller may supply one.
This commit is contained in:
Jean-Paul Calderone 2023-01-02 19:29:13 -05:00
parent 1c643ebbaf
commit 15e22dcc52
5 changed files with 31 additions and 21 deletions

View File

@ -9,17 +9,11 @@ features of any objects that `cryptography` documents.
That is, the public and private keys are opaque objects; DO NOT depend That is, the public and private keys are opaque objects; DO NOT depend
on any of their methods. on any of their methods.
Ported to Python 3.
""" """
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future.utils import PY2 from __future__ import annotations
if PY2:
from builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401 from typing import TypeVar
from cryptography.exceptions import InvalidSignature from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
@ -30,6 +24,8 @@ from cryptography.hazmat.primitives.serialization import load_der_private_key, l
from allmydata.crypto.error import BadSignature from allmydata.crypto.error import BadSignature
PublicKey = TypeVar("PublicKey", bound=rsa.RSAPublicKey)
PrivateKey = TypeVar("PrivateKey", bound=rsa.RSAPrivateKey)
# This is the value that was used by `pycryptopp`, and we must continue to use it for # This is the value that was used by `pycryptopp`, and we must continue to use it for
# both backwards compatibility and interoperability. # both backwards compatibility and interoperability.

View File

@ -1,17 +1,12 @@
""" """
Ported to Python 3. Create file nodes of various types.
""" """
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from future.utils import PY2 from __future__ import annotations
if PY2:
from future.builtins import filter, map, zip, ascii, chr, hex, input, next, oct, open, pow, round, super, bytes, dict, list, object, range, str, max, min # noqa: F401
import weakref import weakref
from zope.interface import implementer from zope.interface import implementer
from twisted.internet.defer import succeed
from allmydata.util.assertutil import precondition from allmydata.util.assertutil import precondition
from allmydata.interfaces import INodeMaker from allmydata.interfaces import INodeMaker
from allmydata.immutable.literal import LiteralFileNode from allmydata.immutable.literal import LiteralFileNode
@ -22,6 +17,7 @@ from allmydata.mutable.publish import MutableData
from allmydata.dirnode import DirectoryNode, pack_children from allmydata.dirnode import DirectoryNode, pack_children
from allmydata.unknown import UnknownNode from allmydata.unknown import UnknownNode
from allmydata.blacklist import ProhibitedNode from allmydata.blacklist import ProhibitedNode
from allmydata.crypto.rsa import PublicKey, PrivateKey
from allmydata import uri from allmydata import uri
@ -126,12 +122,15 @@ class NodeMaker(object):
return self._create_dirnode(filenode) return self._create_dirnode(filenode)
return None return None
def create_mutable_file(self, contents=None, version=None): def create_mutable_file(self, contents=None, version=None, keypair: tuple[PublicKey, PrivateKey] | None = None):
if version is None: if version is None:
version = self.mutable_file_default version = self.mutable_file_default
n = MutableFileNode(self.storage_broker, self.secret_holder, n = MutableFileNode(self.storage_broker, self.secret_holder,
self.default_encoding_parameters, self.history) self.default_encoding_parameters, self.history)
d = self.key_generator.generate() if keypair is None:
d = self.key_generator.generate()
else:
d = succeed(keypair)
d.addCallback(n.create_with_keys, contents, version=version) d.addCallback(n.create_with_keys, contents, version=version)
d.addCallback(lambda res: n) d.addCallback(lambda res: n)
return d return d

View File

@ -30,6 +30,7 @@ from allmydata.mutable.publish import MutableData
from ..test_download import PausingConsumer, PausingAndStoppingConsumer, \ from ..test_download import PausingConsumer, PausingAndStoppingConsumer, \
StoppingConsumer, ImmediatelyStoppingConsumer StoppingConsumer, ImmediatelyStoppingConsumer
from .. import common_util as testutil from .. import common_util as testutil
from ...crypto.rsa import create_signing_keypair
from .util import ( from .util import (
FakeStorage, FakeStorage,
make_nodemaker_with_peers, make_nodemaker_with_peers,
@ -65,6 +66,16 @@ class Filenode(AsyncBrokenTestCase, testutil.ShouldFailMixin):
d.addCallback(_created) d.addCallback(_created)
return d return d
async def test_create_with_keypair(self):
"""
An SDMF can be created using a given keypair.
"""
(priv, pub) = create_signing_keypair(2048)
node = await self.nodemaker.create_mutable_file(keypair=(pub, priv))
self.assertThat(
(node.get_privkey(), node.get_pubkey()),
Equals((priv, pub)),
)
def test_create_mdmf(self): def test_create_mdmf(self):
d = self.nodemaker.create_mutable_file(version=MDMF_VERSION) d = self.nodemaker.create_mutable_file(version=MDMF_VERSION)

View File

@ -1619,7 +1619,8 @@ class FakeMutableFile(object): # type: ignore # incomplete implementation
return defer.succeed(None) return defer.succeed(None)
class FakeNodeMaker(NodeMaker): class FakeNodeMaker(NodeMaker):
def create_mutable_file(self, contents=b"", keysize=None, version=None): def create_mutable_file(self, contents=b"", keysize=None, version=None, keypair=None):
assert keypair is None, "FakeNodeMaker does not support externally supplied keypairs"
return defer.succeed(FakeMutableFile(contents)) return defer.succeed(FakeMutableFile(contents))
class FakeClient2(_Client): # type: ignore # tahoe-lafs/ticket/3573 class FakeClient2(_Client): # type: ignore # tahoe-lafs/ticket/3573

View File

@ -102,7 +102,10 @@ class FakeNodeMaker(NodeMaker):
self.encoding_params, None, self.encoding_params, None,
self.all_contents).init_from_cap(cap) self.all_contents).init_from_cap(cap)
def create_mutable_file(self, contents=b"", keysize=None, def create_mutable_file(self, contents=b"", keysize=None,
version=SDMF_VERSION): version=SDMF_VERSION,
keypair=None,
):
assert keypair is None, "FakeNodeMaker does not support externally supplied keypairs"
n = FakeMutableFileNode(None, None, self.encoding_params, None, n = FakeMutableFileNode(None, None, self.encoding_params, None,
self.all_contents) self.all_contents)
return n.create(contents, version=version) return n.create(contents, version=version)