diff --git a/examples/certificates/peer-certificate-example-encrypted-private-key.der b/examples/certificates/peer-certificate-example-encrypted-private-key.der new file mode 100644 index 000000000..e0d40cedb Binary files /dev/null and b/examples/certificates/peer-certificate-example-encrypted-private-key.der differ diff --git a/examples/certificates/peer-private-key-example-encrypted-private-key.pem b/examples/certificates/peer-private-key-example-encrypted-private-key.pem new file mode 100644 index 000000000..212739bf8 --- /dev/null +++ b/examples/certificates/peer-private-key-example-encrypted-private-key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,E7DD4D5AF801673880EDCD6CDDAB5CAB + +IPEul2koHiKkv2bDAwktnFSWFoEh9GPAxYjHNjFNyHfAdvTsxsVxZcmQJDHtWfae ++d6d2P4FX0KDzXesziLsMnfl7IiycFK6dCVr3K8a/LhVqGlGprz2++ddK1fVlqh2 +xZVXoO2vJ8vKMfhcVbCwXQTeXZj4Y+1JhaAPkwgC3VZ8UKkQ4wCf0baa/fN4VYvW +cAILJWgWX/1j11I5wRtjc8UE3f788d9KLx7nv2g5LoM6N94XLZRFd1eHOW8X33dw +XSEDKBPTfnSybgDbEiCenDnOwTVnT9RrPO1ejA33WY+TpnVFpbT14F4r118YU3wB +OTMGbtUmnmtB2k7Hav0ynyBtFjHUJfkaamARsi9GK0L9X+oEnvG6P/KHw1anLQtH +bsxXZDT7J7qVRtFpoGMfajvFYopl2qVlEsUruuH1nU4coEuKJnRrDL9UBs7ZMTTl +Y0ZXsUhU+dOEDpde9BsCU3cCQbQHt/rjlEQ7kBSHPFrFNzOyvqcC/NtTCroV6wzB +5EuJmTtipZSRZNHTSjROy2TWsgq6W25c63G9VBm3wIj3PgKAkbesdOV8F8F/dZcW +pNLYMKeozDrKrChaSV4s59P7wxc6A3Somx9YrW9Z0PH120tPSezlHbjxCT1rlWre +/eKt/A9BnSLcM8wvMFCHY/vpHKdGan+WUNl6HrNPEqey5fvg7nOC9BmJaZ/X6dr/ +XBE3pGoCxU/mt1H8JTgdrIC8j9izrpklm/Lwv8UoEfeoss2ylkRMWQ+SM1HTVEun +hintzdqmBA83l5oFXbvbopBAhAEx+GlV8v7Iq0npIVZ8qHmHqtjiS9XW7O0+xS82 +yGGkO4cIxt9CWoSxvpYqCVaf7QGWOzmf1La46TBohZ1L4/fifre/JfOaD+oeli4k +qLQlov50fdY5RAOb6oDd4+eR5oMudBN/bhuelXmYzriRk9b2lSU3EFvEpMaqlMCP +9jnj2IXxrfBy4zAyKP6Faa69CiibpZuuXDR3nXXMjDgfRC9gZ/QfjaNQvjgdgSIs +kqj9vzLjGl0UHG7jrZX4qfudAK1n8UCdKQROVs5NfwA2dKdHsbKwKLAWlX6nurKY +hiP6HTGh1J7VCaMC0ml1GCOaVJLkIOKjp5vKr1UWj9bxNkxkezqrGARMevVoEsLB +aQcvI+Q988XsOT1jkZ5NhGjQLxikeDjDHivOAzLVnPAXA4UgDsE8qIr7NVe+lMfI +AxkNAG7FdU9hMsRbO1ofbl1Q+8sfC4CDvj5f1SWXzZjjWsyln1ZpF+RB9mImhOYF +mnTpo+4/4iVaXqvUFGMWaD+km3VkTIWWcuw+KRwr/ZUxqmCEJUr2sVt3pprjtWhr +bDkOd+DyDTfFVKXIcXUNLxxfLu/4hB+mHBLI2gNGiBRpnmckMU/ZmneRtd2P8x5z ++yicrr3kBLFr4l+NtH19Qf9zgqz4UUgFoMzlsrI+vCq3cB87Dr0Txodj4GRhEbAH +LAtNAJNxfarkI0IPsjqooWT/k5wWvtgPI4wW9iCVp2HMVqcaxTV92ayOFgCqwcAM +Yr7E0l20PDEYuEWx5drgDwjoCMXXCdUP939FjDTkRW1wayr+90W3uns8Zl7YKacD +-----END RSA PRIVATE KEY----- diff --git a/tests/test_crypto_connect.py b/tests/test_crypto_connect.py index 4728a18e9..4b3d4d426 100644 --- a/tests/test_crypto_connect.py +++ b/tests/test_crypto_connect.py @@ -1,6 +1,7 @@ import os import pytest import sys + if sys.version_info >= (3, 6): from asyncio import TimeoutError else: @@ -45,6 +46,31 @@ "private_key": f"{EXAMPLE_PATH}certificates/peer-private-key-example-2.pem" } +encrypted_private_key_peer_creds = { + "private_key": f"{EXAMPLE_PATH}certificates/peer-private-key-example-encrypted-private-key.pem", + "certificate": f"{EXAMPLE_PATH}certificates/peer-certificate-example-encrypted-private-key.der", + "password": b"password" +} + + +@pytest.fixture(params=srv_crypto_params) +async def srv_crypto_encrypted_key_one_cert(request): + srv = Server() + peer_certificate = encrypted_private_key_peer_creds["certificate"] + cert_handler = CertificateHandler() + key, cert = request.param + await cert_handler.trust_certificate(peer_certificate) + await srv.init() + srv.set_endpoint(uri_crypto_cert) + srv.set_security_policy([ua.SecurityPolicyType.Basic256Sha256_SignAndEncrypt], + certificate_handler=cert_handler) + await srv.load_certificate(cert) + await srv.load_private_key(key) + await srv.start() + yield srv + # stop the server + await srv.stop() + @pytest.fixture(params=srv_crypto_params) async def srv_crypto_all_certs(request): @@ -101,12 +127,14 @@ async def test_nocrypto(srv_no_crypto): async def test_nocrypto_fail(srv_no_crypto): clt = Client(uri_no_crypto) with pytest.raises(ua.UaError): - await clt.set_security_string(f"Basic256Sha256,Sign,{EXAMPLE_PATH}certificate-example.der,{EXAMPLE_PATH}private-key-example.pem") + await clt.set_security_string( + f"Basic256Sha256,Sign,{EXAMPLE_PATH}certificate-example.der,{EXAMPLE_PATH}private-key-example.pem") async def test_basic256(srv_crypto_all_certs): clt = Client(uri_crypto) - await clt.set_security_string(f"Basic256Sha256,Sign,{EXAMPLE_PATH}certificate-example.der,{EXAMPLE_PATH}private-key-example.pem") + await clt.set_security_string( + f"Basic256Sha256,Sign,{EXAMPLE_PATH}certificate-example.der,{EXAMPLE_PATH}private-key-example.pem") async with clt: assert await clt.nodes.objects.get_children() @@ -114,7 +142,7 @@ async def test_basic256(srv_crypto_all_certs): async def test_basic256_encrypt(srv_crypto_all_certs): clt = Client(uri_crypto) await clt.set_security_string( - f"Basic256Sha256,SignAndEncrypt,{EXAMPLE_PATH}certificate-example.der,{EXAMPLE_PATH}private-key-example.pem") + f"Basic256Sha256,SignAndEncrypt,{EXAMPLE_PATH}certificate-example.der,{EXAMPLE_PATH}private-key-example.pem") async with clt: assert await clt.nodes.objects.get_children() @@ -122,12 +150,12 @@ async def test_basic256_encrypt(srv_crypto_all_certs): async def test_basic256_encrypt_success(srv_crypto_all_certs): clt = Client(uri_crypto) await clt.set_security( - security_policies.SecurityPolicyBasic256Sha256, - f"{EXAMPLE_PATH}certificate-example.der", - f"{EXAMPLE_PATH}private-key-example.pem", - None, - ua.MessageSecurityMode.SignAndEncrypt - ) + security_policies.SecurityPolicyBasic256Sha256, + f"{EXAMPLE_PATH}certificate-example.der", + f"{EXAMPLE_PATH}private-key-example.pem", + None, + mode=ua.MessageSecurityMode.SignAndEncrypt + ) async with clt: assert await clt.nodes.objects.get_children() @@ -141,7 +169,7 @@ async def test_basic256_encrypt_fail(srv_crypto_all_certs): f"{EXAMPLE_PATH}certificate-example.der", f"{EXAMPLE_PATH}private-key-example.pem", None, - ua.MessageSecurityMode.None_ + mode=ua.MessageSecurityMode.None_ ) @@ -152,7 +180,21 @@ async def test_certificate_handling_success(srv_crypto_one_cert): peer_creds['certificate'], peer_creds['private_key'], None, - ua.MessageSecurityMode.SignAndEncrypt + mode=ua.MessageSecurityMode.SignAndEncrypt + ) + async with clt: + assert await clt.get_objects_node().get_children() + + +async def test_encrypted_private_key_handling_success(srv_crypto_encrypted_key_one_cert): + clt = Client(uri_crypto_cert) + await clt.set_security( + security_policies.SecurityPolicyBasic256Sha256, + encrypted_private_key_peer_creds['certificate'], + encrypted_private_key_peer_creds['private_key'], + encrypted_private_key_peer_creds['password'], + None, + mode=ua.MessageSecurityMode.SignAndEncrypt ) async with clt: assert await clt.get_objects_node().get_children() @@ -167,7 +209,23 @@ async def test_certificate_handling_failure(srv_crypto_one_cert): unauthorized_peer_creds['certificate'], unauthorized_peer_creds['private_key'], None, - ua.MessageSecurityMode.SignAndEncrypt + mode=ua.MessageSecurityMode.SignAndEncrypt + ) + async with clt: + assert await clt.get_objects_node().get_children() + + +async def test_encrypted_private_key_handling_failure(srv_crypto_one_cert): + clt = Client(uri_crypto_cert) + + with pytest.raises(TimeoutError): + await clt.set_security( + security_policies.SecurityPolicyBasic256Sha256, + unauthorized_peer_creds['certificate'], + unauthorized_peer_creds['private_key'], + None, # Pass None for an empty password to test incorrect password. + None, + mode=ua.MessageSecurityMode.SignAndEncrypt ) async with clt: assert await clt.get_objects_node().get_children() @@ -181,7 +239,7 @@ async def test_certificate_handling_mismatched_creds(srv_crypto_one_cert): peer_creds['certificate'], unauthorized_peer_creds['private_key'], None, - ua.MessageSecurityMode.SignAndEncrypt + mode=ua.MessageSecurityMode.SignAndEncrypt ) async with clt: assert await clt.get_objects_node().get_children()