localize certificate references on VerifiableNode

pull/447/head
Kieran Prasch 2018-09-22 15:37:42 -07:00
parent 9061da4fdf
commit b255416b1b
2 changed files with 40 additions and 17 deletions

View File

@ -115,8 +115,8 @@ def ecdsa_verify(message: bytes,
def _save_tls_certificate(certificate: Certificate, def _save_tls_certificate(certificate: Certificate,
full_filepath, full_filepath: str,
force: bool = True, force: bool = True, # TODO
) -> str: ) -> str:
if force is False and os.path.isfile(full_filepath): if force is False and os.path.isfile(full_filepath):
raise FileExistsError('A TLS certificate already exists at {}.'.format(full_filepath)) raise FileExistsError('A TLS certificate already exists at {}.'.format(full_filepath))
@ -125,6 +125,8 @@ def _save_tls_certificate(certificate: Certificate,
public_pem_bytes = certificate.public_bytes(Encoding.PEM) public_pem_bytes = certificate.public_bytes(Encoding.PEM)
certificate_file.write(public_pem_bytes) certificate_file.write(public_pem_bytes)
return full_filepath
def load_tls_certificate(filepath: str) -> Certificate: def load_tls_certificate(filepath: str) -> Certificate:
"""Deserialize an X509 certificate from a filepath""" """Deserialize an X509 certificate from a filepath"""
@ -140,10 +142,9 @@ def load_tls_certificate(filepath: str) -> Certificate:
def generate_self_signed_certificate(common_name: str, def generate_self_signed_certificate(common_name: str,
curve: EllipticCurve, curve: EllipticCurve,
host: str, host: str,
certificate_dir: str,
private_key: _EllipticCurvePrivateKey = None, private_key: _EllipticCurvePrivateKey = None,
days_valid: int = 365 days_valid: int = 365
) -> Tuple[Certificate, _EllipticCurvePrivateKey, str]: ) -> Tuple[Certificate, _EllipticCurvePrivateKey]:
if not private_key: if not private_key:
private_key = ec.generate_private_key(curve, default_backend()) private_key = ec.generate_private_key(curve, default_backend())

View File

@ -1,5 +1,8 @@
import os
import OpenSSL import OpenSSL
from constant_sorrow import constants from constant_sorrow import constants
from cryptography.x509 import Certificate
from eth_keys.datatypes import Signature as EthSignature from eth_keys.datatypes import Signature as EthSignature
from nucypher.crypto.api import _save_tls_certificate from nucypher.crypto.api import _save_tls_certificate
@ -17,13 +20,19 @@ class VerifiableNode:
_verified_node = False _verified_node = False
def __init__(self, def __init__(self,
certificate: Certificate,
certificate_filepath: str,
interface_signature=constants.NOT_SIGNED.bool_value(False), interface_signature=constants.NOT_SIGNED.bool_value(False),
certificate_filepath: str = None,
) -> None: ) -> None:
self.certificate_filepath = certificate_filepath # TODO: This gets messy when it is None (although it being None is actually reasonable in some cases, at least for testing). Let's make this a method instead that inspects the TLSHostingPower (similar to get_deployer()). self.certificate = certificate
self.certificate_filepath = certificate_filepath
self._interface_signature_object = interface_signature self._interface_signature_object = interface_signature
# TODO: This gets messy when it is None
# (although it being None is actually reasonable in some cases, at least for testing).
# Let's make this a method instead that inspects the TLSHostingPower (similar to get_deployer()).
class InvalidNode(SuspiciousActivity): class InvalidNode(SuspiciousActivity):
""" """
Raised when a node has an invalid characteristic - stamp, interface, or address. Raised when a node has an invalid characteristic - stamp, interface, or address.
@ -34,6 +43,12 @@ class VerifiableNode:
Raise when a Character tries to use another Character as decentralized when the latter is federated_only. Raise when a Character tries to use another Character as decentralized when the latter is federated_only.
""" """
@classmethod
def from_tls_hosting_power(cls, tls_hosting_power: TLSHostingPower, *args, **kwargs):
certificate_filepath = tls_hosting_power.keypair.certificate_filepath
certificate = tls_hosting_power.keypair.certificate
return cls(certificate=certificate, certificate_filepath=certificate_filepath, *args, **kwargs)
def _stamp_has_valid_wallet_signature(self): def _stamp_has_valid_wallet_signature(self):
signature_bytes = self._evidence_of_decentralized_identity signature_bytes = self._evidence_of_decentralized_identity
if signature_bytes is constants.NOT_SIGNED: if signature_bytes is constants.NOT_SIGNED:
@ -141,21 +156,28 @@ class VerifiableNode:
raise NoSigningPower("This Ursula is a Stranger; you didn't init with an interface signature, so you can't verify.") raise NoSigningPower("This Ursula is a Stranger; you didn't init with an interface signature, so you can't verify.")
return self._interface_signature_object return self._interface_signature_object
def certificate(self): @property
return self._crypto_power.power_ups(TLSHostingPower).keypair.certificate def common_name(self):
x509 = OpenSSL.crypto.X509.from_cryptography(self.certificate)
def save_certificate_to_disk(self, directory):
x509 = OpenSSL.crypto.X509.from_cryptography(self.certificate())
subject_components = x509.get_subject().get_components() subject_components = x509.get_subject().get_components()
common_name_as_bytes = subject_components[0][1] common_name_as_bytes = subject_components[0][1]
common_name_from_cert = common_name_as_bytes.decode() common_name_from_cert = common_name_as_bytes.decode()
return common_name_from_cert
@property
def certificate_filename(self):
return self.common_name + '.pem' # TODO: use cert encoding..?
def save_certificate_to_disk(self, directory):
x509 = OpenSSL.crypto.X509.from_cryptography(self.certificate)
subject_components = x509.get_subject().get_components()
common_name_as_bytes = subject_components[0][1]
common_name_from_cert = common_name_as_bytes.decode()
if not self.checksum_public_address == common_name_from_cert: if not self.checksum_public_address == common_name_from_cert:
# TODO: It's better for us to have checked this a while ago so that this situation is impossible. #443 # TODO: It's better for us to have checked this a while ago so that this situation is impossible. #443
raise ValueError( raise ValueError("You passed a common_name that is not the same one as the cert. Why? FWIW, You don't even need to pass a common name here; the cert will be saved according to the name on the cert itself.")
"You passed a common_name that is not the same one as the cert. Why? FWIW, You don't even need to pass a common name here; the cert will be saved according to the name on the cert itself.")
certificate_filepath = "{}/{}".format(directory,
common_name_from_cert) # TODO: Do this with proper path tooling.
_save_tls_certificate(self.certificate(), full_filepath=certificate_filepath)
certificate_filepath = os.path.join(directory, self.certificate_filename)
_save_tls_certificate(self.certificate, full_filepath=certificate_filepath)
self.certificate_filepath = certificate_filepath self.certificate_filepath = certificate_filepath