Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
opcua-asyncio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nikola Balog
opcua-asyncio
Commits
d5ce251b
Commit
d5ce251b
authored
Oct 16, 2024
by
Christoph Ziebuhr
Committed by
oroulet
Dec 04, 2024
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move SecurityPolicy from ua to crypto
parent
2c9c7aa2
Changes
9
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
234 additions
and
203 deletions
+234
-203
asyncua/client/client.py
asyncua/client/client.py
+6
-6
asyncua/client/ha/ha_client.py
asyncua/client/ha/ha_client.py
+3
-2
asyncua/client/ua_client.py
asyncua/client/ua_client.py
+4
-3
asyncua/crypto/security_policies.py
asyncua/crypto/security_policies.py
+211
-66
asyncua/server/server.py
asyncua/server/server.py
+4
-2
asyncua/server/uaprocessor.py
asyncua/server/uaprocessor.py
+2
-1
asyncua/ua/uaprotocol_hand.py
asyncua/ua/uaprotocol_hand.py
+0
-120
tests/test_ha_client.py
tests/test_ha_client.py
+2
-2
tests/test_unit.py
tests/test_unit.py
+2
-1
No files found.
asyncua/client/client.py
View file @
d5ce251b
...
...
@@ -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
...
...
asyncua/client/ha/ha_client.py
View file @
d5ce251b
...
...
@@ -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
,
...
...
asyncua/client/ua_client.py
View file @
d5ce251b
...
...
@@ -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
):
...
...
asyncua/crypto/security_policies.py
View file @
d5ce251b
This diff is collapsed.
Click to expand it.
asyncua/server/server.py
View file @
d5ce251b
...
...
@@ -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
,
...
...
asyncua/server/uaprocessor.py
View file @
d5ce251b
...
...
@@ -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
...
...
asyncua/ua/uaprotocol_hand.py
View file @
d5ce251b
...
...
@@ -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
...
...
tests/test_ha_client.py
View file @
d5ce251b
...
...
@@ -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
...
...
tests/test_unit.py
View file @
d5ce251b
...
...
@@ -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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment