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:
self.description = self.name
self.application_uri = "urn:freeopcua: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_timeout = 3600000 # 1 hour
self.session_timeout = 3600000 # 1 hour
......@@ -162,7 +162,7 @@ class Client:
async def set_security_string(self, string: str) -> None:
"""
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:
- ``Policy`` is ``Basic128Rsa15``, ``Basic256`` or ``Basic256Sha256``
- ``Mode`` is ``Sign`` or ``SignAndEncrypt``
......@@ -190,7 +190,7 @@ class Client:
async def set_security(
self,
policy: Type[ua.SecurityPolicy],
policy: Type[security_policies.SecurityPolicy],
certificate: Union[str, uacrypto.CertProperties, bytes, Path],
private_key: Union[str, uacrypto.CertProperties, bytes, Path],
private_key_password: Optional[Union[str, bytes]] = None,
......@@ -203,7 +203,7 @@ class Client:
"""
if server_certificate is None:
# Force unencrypted/unsigned SecureChannel to list the endpoints
new_policy = ua.SecurityPolicy()
new_policy = security_policies.SecurityPolicyNone()
self.security_policy = new_policy
self.uaclient.security_policy = new_policy
# load certificate from server's list of endpoints
......@@ -226,7 +226,7 @@ class Client:
async def _set_security(
self,
policy: Type[ua.SecurityPolicy],
policy: Type[security_policies.SecurityPolicy],
certificate: uacrypto.CertProperties,
private_key: uacrypto.CertProperties,
server_cert: uacrypto.CertProperties,
......@@ -699,7 +699,7 @@ class Client:
params.UserIdentityToken = ua.UserNameIdentityToken()
params.UserIdentityToken.UserName = 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,
# then the password only contains UTF-8 encoded password
# and EncryptionAlgorithm is null
......
......@@ -16,6 +16,7 @@ from .reconciliator import Reconciliator
from .common import ClientNotFound, event_wait
from .virtual_subscription import TypeSubHandler, VirtualSubscription
from ...crypto.uacrypto import CertProperties
from ...crypto.security_policies import SecurityPolicy
_logger = logging.getLogger(__name__)
......@@ -64,7 +65,7 @@ class ServerInfo:
@dataclass(frozen=True, eq=True)
class HaSecurityConfig:
policy: Optional[Type[ua.SecurityPolicy]] = None
policy: Optional[Type[SecurityPolicy]] = None
certificate: Optional[CertProperties] = None
private_key: Optional[CertProperties] = None
server_certificate: Optional[CertProperties] = None
......@@ -190,7 +191,7 @@ class HaClient:
def set_security(
self,
policy: Type[ua.SecurityPolicy],
policy: Type[SecurityPolicy],
certificate: CertProperties,
private_key: CertProperties,
server_certificate: Optional[CertProperties] = None,
......
......@@ -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.uaprotocol_auto import OpenSecureChannelResult, SubscriptionAcknowledgement
from ..common.connection import SecureConnection, TransportLimits
from ..crypto import security_policies
class UASocketProtocol(asyncio.Protocol):
......@@ -29,7 +30,7 @@ class UASocketProtocol(asyncio.Protocol):
def __init__(
self,
timeout: float = 1,
security_policy: ua.SecurityPolicy = ua.SecurityPolicy(),
security_policy: security_policies.SecurityPolicy = security_policies.SecurityPolicyNone(),
limits: TransportLimits = None,
):
"""
......@@ -293,13 +294,13 @@ class UaClient(AbstractSession):
self.logger = logging.getLogger(f"{__name__}.UaClient")
self._subscription_callbacks = {}
self._timeout = timeout
self.security_policy = ua.SecurityPolicy()
self.security_policy = security_policies.SecurityPolicyNone()
self.protocol: UASocketProtocol = None
self._publish_task = None
self._pre_request_hook: Optional[Callable[[], Awaitable[None]]] = None
self._closing: bool = False
def set_security(self, policy: ua.SecurityPolicy):
def set_security(self, policy: security_policies.SecurityPolicy):
self.security_policy = policy
def _make_protocol(self):
......
This diff is collapsed.
......@@ -384,12 +384,14 @@ class Server:
no_cert = False
for policy_type in self._security_policy:
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
continue
self._set_endpoints(policy, mode, level)
self._policies.append(
ua.SecurityPolicyFactory(
security_policies.SecurityPolicyFactory(
policy,
mode,
self.certificate,
......
......@@ -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 ..common.connection import SecureConnection, TransportLimits
from ..common.utils import ServiceError
from ..crypto.security_policies import SecurityPolicyNone
_logger = logging.getLogger(__name__)
......@@ -40,7 +41,7 @@ class UaProcessor:
# rely on dict insertion order (therefore can't use set())
self._publish_results_subs: Dict[ua.IntegerId, bool] = {}
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._session_watchdog_task: Optional[asyncio.Task] = None
self._watchdog_interval: float = 1.0
......
......@@ -110,126 +110,6 @@ class SequenceHeader:
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:
def __init__(self, chunks):
self._chunks = chunks
......
......@@ -248,8 +248,8 @@ class TestHaClient:
await wait_clients_socket(ha_client, UASocketProtocol.OPEN)
for client in ha_client.get_clients():
assert isinstance(client.security_policy, ua.SecurityPolicy)
assert isinstance(client.uaclient.security_policy, ua.SecurityPolicy)
assert isinstance(client.security_policy, security_policies.SecurityPolicy)
assert isinstance(client.uaclient.security_policy, security_policies.SecurityPolicy)
assert client.security_policy.Mode == security_mode
assert client.security_policy.peer_certificate
......
......@@ -25,6 +25,7 @@ from asyncua.common.ua_utils import string_to_val, val_to_string
from asyncua.ua.uatypes import _MaskEnum
from asyncua.common.structures import StructGenerator
from asyncua.common.connection import MessageChunk
from asyncua.crypto.security_policies import SecurityPolicyNone
EXAMPLE_BSD_PATH = Path(__file__).parent.absolute() / "example.bsd"
......@@ -728,7 +729,7 @@ def test_text_with_locale():
def test_message_chunk():
pol = ua.SecurityPolicy()
pol = SecurityPolicyNone()
chunks = MessageChunk.message_to_chunks(pol, b"123", 65536)
assert len(chunks) == 1
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