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:
...
@@ -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
...
...
asyncua/client/ha/ha_client.py
View file @
d5ce251b
...
@@ -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
,
...
...
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
...
@@ -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
):
...
...
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:
...
@@ -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
,
...
...
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
...
@@ -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
...
...
asyncua/ua/uaprotocol_hand.py
View file @
d5ce251b
...
@@ -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
...
...
tests/test_ha_client.py
View file @
d5ce251b
...
@@ -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
...
...
tests/test_unit.py
View file @
d5ce251b
...
@@ -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
...
...
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