Commit d5ce251b authored by Christoph Ziebuhr's avatar Christoph Ziebuhr Committed by oroulet

Move SecurityPolicy from ua to crypto

parent 2c9c7aa2
...@@ -68,7 +68,7 @@ class Client: ...@@ -68,7 +68,7 @@ class Client:
self.description = self.name self.description = self.name
self.application_uri = "urn:freeopcua:client" self.application_uri = "urn:freeopcua:client"
self.product_uri = "urn:freeopcua.github.io:client" self.product_uri = "urn:freeopcua.github.io:client"
self.security_policy = ua.SecurityPolicy() self.security_policy = security_policies.SecurityPolicyNone()
self.secure_channel_id = None self.secure_channel_id = None
self.secure_channel_timeout = 3600000 # 1 hour self.secure_channel_timeout = 3600000 # 1 hour
self.session_timeout = 3600000 # 1 hour self.session_timeout = 3600000 # 1 hour
...@@ -162,7 +162,7 @@ class Client: ...@@ -162,7 +162,7 @@ class Client:
async def set_security_string(self, string: str) -> None: async def set_security_string(self, string: str) -> None:
""" """
Set SecureConnection mode. Set SecureConnection mode.
:param string: Mode format ``Policy,Mode,certificate,private_key[,server_private_key]`` :param string: Mode format ``Policy,Mode,certificate,private_key[,server_certificate]``
where: where:
- ``Policy`` is ``Basic128Rsa15``, ``Basic256`` or ``Basic256Sha256`` - ``Policy`` is ``Basic128Rsa15``, ``Basic256`` or ``Basic256Sha256``
- ``Mode`` is ``Sign`` or ``SignAndEncrypt`` - ``Mode`` is ``Sign`` or ``SignAndEncrypt``
...@@ -190,7 +190,7 @@ class Client: ...@@ -190,7 +190,7 @@ class Client:
async def set_security( async def set_security(
self, self,
policy: Type[ua.SecurityPolicy], policy: Type[security_policies.SecurityPolicy],
certificate: Union[str, uacrypto.CertProperties, bytes, Path], certificate: Union[str, uacrypto.CertProperties, bytes, Path],
private_key: Union[str, uacrypto.CertProperties, bytes, Path], private_key: Union[str, uacrypto.CertProperties, bytes, Path],
private_key_password: Optional[Union[str, bytes]] = None, private_key_password: Optional[Union[str, bytes]] = None,
...@@ -203,7 +203,7 @@ class Client: ...@@ -203,7 +203,7 @@ class Client:
""" """
if server_certificate is None: if server_certificate is None:
# Force unencrypted/unsigned SecureChannel to list the endpoints # Force unencrypted/unsigned SecureChannel to list the endpoints
new_policy = ua.SecurityPolicy() new_policy = security_policies.SecurityPolicyNone()
self.security_policy = new_policy self.security_policy = new_policy
self.uaclient.security_policy = new_policy self.uaclient.security_policy = new_policy
# load certificate from server's list of endpoints # load certificate from server's list of endpoints
...@@ -226,7 +226,7 @@ class Client: ...@@ -226,7 +226,7 @@ class Client:
async def _set_security( async def _set_security(
self, self,
policy: Type[ua.SecurityPolicy], policy: Type[security_policies.SecurityPolicy],
certificate: uacrypto.CertProperties, certificate: uacrypto.CertProperties,
private_key: uacrypto.CertProperties, private_key: uacrypto.CertProperties,
server_cert: uacrypto.CertProperties, server_cert: uacrypto.CertProperties,
...@@ -699,7 +699,7 @@ class Client: ...@@ -699,7 +699,7 @@ class Client:
params.UserIdentityToken = ua.UserNameIdentityToken() params.UserIdentityToken = ua.UserNameIdentityToken()
params.UserIdentityToken.UserName = username params.UserIdentityToken.UserName = username
policy_uri = self.server_policy_uri(ua.UserTokenType.UserName) policy_uri = self.server_policy_uri(ua.UserTokenType.UserName)
if not policy_uri or policy_uri == security_policies.POLICY_NONE_URI: if not policy_uri or policy_uri == security_policies.SecurityPolicyNone.URI:
# see specs part 4, 7.36.3: if the token is NOT encrypted, # see specs part 4, 7.36.3: if the token is NOT encrypted,
# then the password only contains UTF-8 encoded password # then the password only contains UTF-8 encoded password
# and EncryptionAlgorithm is null # and EncryptionAlgorithm is null
......
...@@ -16,6 +16,7 @@ from .reconciliator import Reconciliator ...@@ -16,6 +16,7 @@ from .reconciliator import Reconciliator
from .common import ClientNotFound, event_wait from .common import ClientNotFound, event_wait
from .virtual_subscription import TypeSubHandler, VirtualSubscription from .virtual_subscription import TypeSubHandler, VirtualSubscription
from ...crypto.uacrypto import CertProperties from ...crypto.uacrypto import CertProperties
from ...crypto.security_policies import SecurityPolicy
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
...@@ -64,7 +65,7 @@ class ServerInfo: ...@@ -64,7 +65,7 @@ class ServerInfo:
@dataclass(frozen=True, eq=True) @dataclass(frozen=True, eq=True)
class HaSecurityConfig: class HaSecurityConfig:
policy: Optional[Type[ua.SecurityPolicy]] = None policy: Optional[Type[SecurityPolicy]] = None
certificate: Optional[CertProperties] = None certificate: Optional[CertProperties] = None
private_key: Optional[CertProperties] = None private_key: Optional[CertProperties] = None
server_certificate: Optional[CertProperties] = None server_certificate: Optional[CertProperties] = None
...@@ -190,7 +191,7 @@ class HaClient: ...@@ -190,7 +191,7 @@ class HaClient:
def set_security( def set_security(
self, self,
policy: Type[ua.SecurityPolicy], policy: Type[SecurityPolicy],
certificate: CertProperties, certificate: CertProperties,
private_key: CertProperties, private_key: CertProperties,
server_certificate: Optional[CertProperties] = None, server_certificate: Optional[CertProperties] = None,
......
...@@ -14,6 +14,7 @@ from ..ua.ua_binary import struct_from_binary, uatcp_to_binary, struct_to_binary ...@@ -14,6 +14,7 @@ from ..ua.ua_binary import struct_from_binary, uatcp_to_binary, struct_to_binary
from ..ua.uaerrors import BadTimeout, BadNoSubscription, BadSessionClosed, BadUserAccessDenied, UaStructParsingError from ..ua.uaerrors import BadTimeout, BadNoSubscription, BadSessionClosed, BadUserAccessDenied, UaStructParsingError
from ..ua.uaprotocol_auto import OpenSecureChannelResult, SubscriptionAcknowledgement from ..ua.uaprotocol_auto import OpenSecureChannelResult, SubscriptionAcknowledgement
from ..common.connection import SecureConnection, TransportLimits from ..common.connection import SecureConnection, TransportLimits
from ..crypto import security_policies
class UASocketProtocol(asyncio.Protocol): class UASocketProtocol(asyncio.Protocol):
...@@ -29,7 +30,7 @@ class UASocketProtocol(asyncio.Protocol): ...@@ -29,7 +30,7 @@ class UASocketProtocol(asyncio.Protocol):
def __init__( def __init__(
self, self,
timeout: float = 1, timeout: float = 1,
security_policy: ua.SecurityPolicy = ua.SecurityPolicy(), security_policy: security_policies.SecurityPolicy = security_policies.SecurityPolicyNone(),
limits: TransportLimits = None, limits: TransportLimits = None,
): ):
""" """
...@@ -293,13 +294,13 @@ class UaClient(AbstractSession): ...@@ -293,13 +294,13 @@ class UaClient(AbstractSession):
self.logger = logging.getLogger(f"{__name__}.UaClient") self.logger = logging.getLogger(f"{__name__}.UaClient")
self._subscription_callbacks = {} self._subscription_callbacks = {}
self._timeout = timeout self._timeout = timeout
self.security_policy = ua.SecurityPolicy() self.security_policy = security_policies.SecurityPolicyNone()
self.protocol: UASocketProtocol = None self.protocol: UASocketProtocol = None
self._publish_task = None self._publish_task = None
self._pre_request_hook: Optional[Callable[[], Awaitable[None]]] = None self._pre_request_hook: Optional[Callable[[], Awaitable[None]]] = None
self._closing: bool = False self._closing: bool = False
def set_security(self, policy: ua.SecurityPolicy): def set_security(self, policy: security_policies.SecurityPolicy):
self.security_policy = policy self.security_policy = policy
def _make_protocol(self): def _make_protocol(self):
......
This diff is collapsed.
...@@ -384,12 +384,14 @@ class Server: ...@@ -384,12 +384,14 @@ class Server:
no_cert = False no_cert = False
for policy_type in self._security_policy: for policy_type in self._security_policy:
policy, mode, level = security_policies.SECURITY_POLICY_TYPE_MAP[policy_type] policy, mode, level = security_policies.SECURITY_POLICY_TYPE_MAP[policy_type]
if policy is not ua.SecurityPolicy and not (self.certificate and self.iserver.private_key): if policy is not security_policies.SecurityPolicyNone and not (
self.certificate and self.iserver.private_key
):
no_cert = True no_cert = True
continue continue
self._set_endpoints(policy, mode, level) self._set_endpoints(policy, mode, level)
self._policies.append( self._policies.append(
ua.SecurityPolicyFactory( security_policies.SecurityPolicyFactory(
policy, policy,
mode, mode,
self.certificate, self.certificate,
......
...@@ -11,6 +11,7 @@ from ..ua.ua_binary import nodeid_from_binary, struct_from_binary, struct_to_bin ...@@ -11,6 +11,7 @@ from ..ua.ua_binary import nodeid_from_binary, struct_from_binary, struct_to_bin
from .internal_server import InternalServer, InternalSession from .internal_server import InternalServer, InternalSession
from ..common.connection import SecureConnection, TransportLimits from ..common.connection import SecureConnection, TransportLimits
from ..common.utils import ServiceError from ..common.utils import ServiceError
from ..crypto.security_policies import SecurityPolicyNone
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
...@@ -40,7 +41,7 @@ class UaProcessor: ...@@ -40,7 +41,7 @@ class UaProcessor:
# rely on dict insertion order (therefore can't use set()) # rely on dict insertion order (therefore can't use set())
self._publish_results_subs: Dict[ua.IntegerId, bool] = {} self._publish_results_subs: Dict[ua.IntegerId, bool] = {}
self._limits = copy.deepcopy(limits) # Copy limits because they get overriden self._limits = copy.deepcopy(limits) # Copy limits because they get overriden
self._connection = SecureConnection(ua.SecurityPolicy(), self._limits) self._connection = SecureConnection(SecurityPolicyNone(), self._limits)
self._closing: bool = False self._closing: bool = False
self._session_watchdog_task: Optional[asyncio.Task] = None self._session_watchdog_task: Optional[asyncio.Task] = None
self._watchdog_interval: float = 1.0 self._watchdog_interval: float = 1.0
......
...@@ -110,126 +110,6 @@ class SequenceHeader: ...@@ -110,126 +110,6 @@ class SequenceHeader:
return struct.calcsize("<II") return struct.calcsize("<II")
class CryptographyNone:
"""
Base class for symmetric/asymmetric cryptography
"""
def __init__(self):
pass
def plain_block_size(self):
"""
Size of plain text block for block cipher.
"""
return 1
def encrypted_block_size(self):
"""
Size of encrypted text block for block cipher.
"""
return 1
def padding(self, size):
"""
Create padding for a block of given size.
plain_size = size + len(padding) + signature_size()
plain_size = N * plain_block_size()
"""
return b""
def min_padding_size(self):
return 0
def signature_size(self):
return 0
def signature(self, data):
return b""
def encrypt(self, data):
return data
def decrypt(self, data):
return data
def vsignature_size(self):
return 0
def verify(self, data, signature):
"""
Verify signature and raise exception if signature is invalid
"""
pass
def remove_padding(self, data):
return data
class SecurityPolicy:
"""
Base class for security policy
"""
URI = "http://opcfoundation.org/UA/SecurityPolicy#None"
AsymmetricSignatureURI: str = ""
signature_key_size: int = 0
symmetric_key_size: int = 0
secure_channel_nonce_length: int = 0
def __init__(self, permissions=None):
self.asymmetric_cryptography = CryptographyNone()
self.symmetric_cryptography = CryptographyNone()
self.Mode = auto.MessageSecurityMode.None_
self.peer_certificate = None
self.host_certificate = None
self.user = None
self.permissions = permissions
def make_local_symmetric_key(self, secret, seed):
pass
def make_remote_symmetric_key(self, secret, seed, lifetime):
pass
class SecurityPolicyFactory:
"""
Helper class for creating server-side SecurityPolicy.
Server has one certificate and private key, but needs a separate
SecurityPolicy for every client and client's certificate
"""
def __init__(
self,
cls=SecurityPolicy,
mode=auto.MessageSecurityMode.None_,
certificate=None,
private_key=None,
permission_ruleset=None,
):
self.cls = cls
self.mode = mode
self.certificate = certificate
self.private_key = private_key
self.permission_ruleset = permission_ruleset
def matches(self, uri, mode=None):
return self.cls.URI == uri and (mode is None or self.mode == mode)
def create(self, peer_certificate):
if self.cls is SecurityPolicy:
return self.cls(permissions=self.permission_ruleset)
else:
return self.cls(
peer_certificate,
self.certificate,
self.private_key,
self.mode,
permission_ruleset=self.permission_ruleset,
)
class Message: class Message:
def __init__(self, chunks): def __init__(self, chunks):
self._chunks = chunks self._chunks = chunks
......
...@@ -248,8 +248,8 @@ class TestHaClient: ...@@ -248,8 +248,8 @@ class TestHaClient:
await wait_clients_socket(ha_client, UASocketProtocol.OPEN) await wait_clients_socket(ha_client, UASocketProtocol.OPEN)
for client in ha_client.get_clients(): for client in ha_client.get_clients():
assert isinstance(client.security_policy, ua.SecurityPolicy) assert isinstance(client.security_policy, security_policies.SecurityPolicy)
assert isinstance(client.uaclient.security_policy, ua.SecurityPolicy) assert isinstance(client.uaclient.security_policy, security_policies.SecurityPolicy)
assert client.security_policy.Mode == security_mode assert client.security_policy.Mode == security_mode
assert client.security_policy.peer_certificate assert client.security_policy.peer_certificate
......
...@@ -25,6 +25,7 @@ from asyncua.common.ua_utils import string_to_val, val_to_string ...@@ -25,6 +25,7 @@ from asyncua.common.ua_utils import string_to_val, val_to_string
from asyncua.ua.uatypes import _MaskEnum from asyncua.ua.uatypes import _MaskEnum
from asyncua.common.structures import StructGenerator from asyncua.common.structures import StructGenerator
from asyncua.common.connection import MessageChunk from asyncua.common.connection import MessageChunk
from asyncua.crypto.security_policies import SecurityPolicyNone
EXAMPLE_BSD_PATH = Path(__file__).parent.absolute() / "example.bsd" EXAMPLE_BSD_PATH = Path(__file__).parent.absolute() / "example.bsd"
...@@ -728,7 +729,7 @@ def test_text_with_locale(): ...@@ -728,7 +729,7 @@ def test_text_with_locale():
def test_message_chunk(): def test_message_chunk():
pol = ua.SecurityPolicy() pol = SecurityPolicyNone()
chunks = MessageChunk.message_to_chunks(pol, b"123", 65536) chunks = MessageChunk.message_to_chunks(pol, b"123", 65536)
assert len(chunks) == 1 assert len(chunks) == 1
seq = 0 seq = 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment