open62541 / open62541

Open source implementation of OPC UA (OPC Unified Architecture) aka IEC 62541 licensed under Mozilla Public License v2.0
http://open62541.org
Mozilla Public License 2.0
2.59k stars 1.24k forks source link

server_encryption.c: no encrypting SecurityPolicy #5745

Open growgreat77 opened 1 year ago

growgreat77 commented 1 year ago

Description

Hi, I am using the "server_encryption.c" example, and I have generated "server_cert.der" and "server_key.der" under the "tools" directory. However, when I run the server, the prompt shows that there is no encryption: "AccessControl: Unconfigured AccessControl. Users have all permissions."Below are the detailed information. What could be the reason for this?

ysm@ysm:~/opcua1/bin$ ./server ../certs/server_cert.der ../certs/server_key.der ../certs/client_cert.der
[2023-04-18 13:42:43.109 (UTC+0800)] info/eventloop Starting the EventLoop
[2023-04-18 13:42:43.110 (UTC+0800)] warn/server    AccessControl: Unconfigured AccessControl. Users have all permissions.
[2023-04-18 13:42:43.110 (UTC+0800)] info/server    AccessControl: Anonymous login is enabled
[2023-04-18 13:42:43.110 (UTC+0800)] info/server    AccessControl: x509 certificate user authentication is enabled
[2023-04-18 13:42:43.110 (UTC+0800)] warn/server    Username/Password Authentication configured, but no encrypting SecurityPolicy. This can leak credentials on the network.
[2023-04-18 13:42:43.110 (UTC+0800)] warn/userland  AcceptAll Certificate Verification. Any remote certificate will be accepted.
[2023-04-18 13:42:43.247 (UTC+0800)] warn/userland  ServerUrls already set. Overriding.
[2023-04-18 13:42:43.249 (UTC+0800)] info/securitypolicy    The Basic128Rsa15 security policy with openssl is added.
[2023-04-18 13:42:43.251 (UTC+0800)] info/securitypolicy    The basic256 security policy with openssl is added.
[2023-04-18 13:42:43.252 (UTC+0800)] info/securitypolicy    The basic256sha256 security policy with openssl is added.
[2023-04-18 13:42:43.254 (UTC+0800)] info/securitypolicy    The Aes128Sha256RsaOaep security policy with openssl is added.
[2023-04-18 13:42:43.255 (UTC+0800)] warn/server    AccessControl: Unconfigured AccessControl. Users have all permissions.
[2023-04-18 13:42:43.255 (UTC+0800)] info/server    AccessControl: Anonymous login is enabled
[2023-04-18 13:42:43.258 (UTC+0800)] info/network   TCP | Listening on all interfaces
[2023-04-18 13:42:43.258 (UTC+0800)] info/network   TCP 4   | Creating server socket for "0.0.0.0" on port 4840
[2023-04-18 13:42:43.258 (UTC+0800)] info/network   TCP 5   | Creating server socket for "::" on port 4840
[2023-04-18 13:42:43.258 (UTC+0800)] info/network   TCP 6   | Creating server socket for "127.0.1.1" on port 4840

This is my file directory.

├── bin
│   ├── client
│   └── server
├── build
├── certs
│   ├── client_cert.der
│   ├── client_key.der
│   ├── create_self-signed.py
│   ├── localhost.cnf
│   ├── REAMME.MD
│   ├── server_cert.der
│   └── server_key.der
├── CMakeLists.txt
├── open62541
│   ├── open62541.c
│   └── open62541.h
└── src
    ├── client.c
    ├── common.h
    └── server.c

This is the encryption certificate information of my server.

ysm@ysm:~/opcua1/certs$ openssl x509 -in server_cert.der -inform der -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            26:81:07:39:ed:7d:2f:0f:b1:ac:be:4f:95:1b:5d:e5:7e:b6:c5:a4
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = DE, L = Here, O = open62541, CN = open62541Server@localhost
        Validity
            Not Before: Apr 18 03:06:50 2023 GMT
            Not After : Apr 17 03:06:50 2024 GMT
        Subject: C = DE, L = Here, O = open62541, CN = open62541Server@localhost
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:f1:16:01:44:9b:17:5d:0e:84:32:93:08:00:81:
                    c4:09:da:ca:27:a0:88:f3:c3:f2:c6:0b:46:a3:e0:
                    6c:7c:b3:c5:6d:18:75:bb:ee:59:54:5e:a8:55:14:
                    08:08:9d:a1:08:c1:bd:b4:91:2e:bb:95:f0:58:73:
                    3c:4e:67:94:dd:1f:b2:62:c3:c9:e7:9f:54:77:d2:
                    b7:f5:c7:28:aa:6a:5b:26:a3:89:73:a4:80:11:87:
                    d1:5e:17:f7:02:60:49:0b:24:4a:90:f8:d4:f3:b8:
                    8c:32:24:4a:42:e6:a8:2f:21:eb:cb:1e:a9:19:bb:
                    b1:8f:80:a0:d2:aa:04:5f:7d:2a:2b:40:bb:78:a4:
                    67:b5:6e:79:0e:52:73:3f:b3:8d:cb:57:71:3d:f4:
                    e0:7d:de:d4:45:84:f1:93:b7:67:8f:dc:24:61:76:
                    72:dc:b3:53:49:86:11:d4:54:57:95:fa:dc:58:44:
                    67:d0:36:67:57:65:e0:01:19:a5:2d:a1:ca:c8:f7:
                    5d:75:41:fb:64:3b:6a:f2:17:c4:43:0b:74:8c:b1:
                    72:fe:be:4d:8a:41:df:b1:49:b2:2f:2b:91:a8:8d:
                    ed:db:3e:ad:20:87:d8:37:95:5d:61:09:39:a3:2c:
                    4c:9c:30:29:0b:99:83:9b:66:99:c9:28:ca:72:f7:
                    51:0b
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                86:63:F9:F5:B9:43:6E:7C:C6:CD:3A:C8:42:65:6A:5C:D2:B9:BD:6C
            X509v3 Authority Key Identifier: 
                86:63:F9:F5:B9:43:6E:7C:C6:CD:3A:C8:42:65:6A:5C:D2:B9:BD:6C
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Certificate Sign
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Alternative Name: 
                DNS:ysm, DNS:ysm, IP Address:192.168.40.136, IP Address:127.0.0.1, URI:urn:open62541.server.application
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        10:04:5f:40:c6:92:bb:32:d0:a9:13:3f:c5:ce:37:d8:f4:9e:
        2b:5e:6a:32:58:82:6b:db:f8:06:df:e5:94:a7:a5:3e:b1:ff:
        0d:9a:d1:79:8d:dd:4d:8b:32:34:73:1a:3e:b1:05:2d:25:2c:
        52:92:13:04:4e:0b:37:14:87:4f:0c:f3:f1:01:04:06:d0:78:
        7d:65:46:13:b6:40:5d:80:61:23:99:cc:79:78:6b:d8:e9:4c:
        40:09:37:2f:f8:b4:a6:13:c9:d2:ed:c1:c3:a3:ce:a5:c0:cc:
        6d:76:74:55:83:ae:35:01:cd:98:d2:63:f1:fd:14:42:01:b9:
        75:02:08:14:2b:2f:08:05:5b:34:5f:a9:88:94:a3:68:63:94:
        8e:35:57:ed:38:2c:ca:ec:1c:fe:11:15:b1:c9:6e:8e:be:a0:
        18:0f:7a:60:f6:4a:c6:09:5f:95:46:8d:e3:a8:83:1e:af:9e:
        1d:a2:51:19:12:49:3e:ab:46:0d:bb:c8:d8:63:6c:a3:32:95:
        cf:37:22:45:26:d7:12:51:ca:20:84:8d:54:6b:20:c6:a3:81:
        cd:dd:c8:bc:f3:b6:1c:08:74:f4:6f:ac:19:92:a1:98:d2:8f:
        c7:54:80:c3:a2:12:f0:16:30:71:09:c0:05:6e:f1:e7:8c:ea:

Background Information / Reproduction Steps

Used CMake options:

git clone http://github.com/open62541/open62541.git
cd open62541
sudo apt-get update
git submodule update --init --recursive
mkdir build && cd build
cmake .. -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_NAMESPACE_ZERO=FULL -DUA_ENABLE_AMALGAMATION=ON -DUA_ENABLE_ENCRYPTION=ON -DUA_ENABLE_ENCRYPTION_OPENSSL=ON -DUA_ENABLE_ENCRYPTION_MBEDTLS=OFF
make
sudo make install

This is the code for my server.c

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *
 */

#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>
#include <open62541/plugin/create_certificate.h>
#include <open62541/plugin/securitypolicy.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>

#include <signal.h>
#include <stdlib.h>

#include "common.h"

UA_Boolean running = true;
static void stopHandler(int sig) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
    running = false;
}

int main(int argc, char* argv[]) {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);
    UA_ByteString certificate = UA_BYTESTRING_NULL;
    UA_ByteString privateKey = UA_BYTESTRING_NULL;
    if(argc >= 3) {
        /* Load certificate and private key */
        certificate = loadFile(argv[1]);
        privateKey = loadFile(argv[2]);
    } else {
        UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "Missing arguments. Arguments are "
                     "<server-certificate.der> <private-key.der> "
                     "[<trustlist1.crl>, ...]");
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Trying to create a certificate.");
        UA_String subject[3] = {UA_STRING_STATIC("C=DE"),
                            UA_STRING_STATIC("O=SampleOrganization"),
                            UA_STRING_STATIC("CN=Open62541Server@localhost")};
        UA_UInt32 lenSubject = 3;
        UA_String subjectAltName[2]= {
            UA_STRING_STATIC("DNS:localhost"),
            UA_STRING_STATIC("URI:urn:open62541.server.application")
        };
        UA_UInt32 lenSubjectAltName = 2;
        UA_StatusCode statusCertGen =
            UA_CreateCertificate(UA_Log_Stdout,
                                 subject, lenSubject,
                                 subjectAltName, lenSubjectAltName,
                                 0, UA_CERTIFICATEFORMAT_DER,
                                 &privateKey, &certificate);

        if(statusCertGen != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                "Generating Certificate failed: %s",
                UA_StatusCode_name(statusCertGen));
            return EXIT_SUCCESS;
        }
#else
        return EXIT_SUCCESS;
#endif
    }

    /* Load the trustlist */
    size_t trustListSize = 0;
    if(argc > 3)
        trustListSize = (size_t)argc-3;
    UA_STACKARRAY(UA_ByteString, trustList, trustListSize+1);
    for(size_t i = 0; i < trustListSize; i++)
        trustList[i] = loadFile(argv[i+3]);

    /* Loading of an issuer list, not used in this application */
    size_t issuerListSize = 0;
    UA_ByteString *issuerList = NULL;

    /* Loading of a revocation list currently unsupported */
    UA_ByteString *revocationList = NULL;
    size_t revocationListSize = 0;

    UA_Server *server = UA_Server_new();
    UA_ServerConfig *config = UA_Server_getConfig(server);

    UA_StatusCode retval =
        UA_ServerConfig_setDefaultWithSecurityPolicies(config, 4840,
                                                       &certificate, &privateKey,
                                                       trustList, trustListSize,
                                                       issuerList, issuerListSize,
                                                       revocationList, revocationListSize);

    #ifdef UA_ENABLE_WEBSOCKET_SERVER
    UA_ServerConfig_addNetworkLayerWS(UA_Server_getConfig(server), 7681, 0, 0, &certificate, &privateKey);
    #endif

    UA_ByteString_clear(&certificate);
    UA_ByteString_clear(&privateKey);
    for(size_t i = 0; i < trustListSize; i++)
        UA_ByteString_clear(&trustList[i]);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    if(!running)
        goto cleanup; /* received ctrl-c already */

    retval = UA_Server_run(server, &running);

 cleanup:
    UA_Server_delete(server);
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}

Checklist

Please provide the following information:

growgreat77 commented 1 year ago

And I can indeed log in anonymously using Softing OPC client without any encryption certificates. https://industrial.softing.com/products/opc-ua-and-opc-classic-sdks/opc-ua-demo-client.ht

neojaw commented 1 year ago

Encryption and AccessControl are different things. The Encryption setup and the certificates take care of the encryption of the connection, AccessControl controls what the user can do with an established connection (encrypted or unencrypted).

AccessControl is realized as a plug in that you have to set up yourself to reflect the internal user/permission management of your application. Take a look at the examples/access_control folder to get an idea.

As for the unencrypted connection, you are using UA_ServerConfig_setDefaultWithSecurityPolicies() which includes the None security policy which allows connection without encryption. If you want to prevent that, you have to add the desired security policies manually with the UA_ServerConfig_addSecurityPolicy*() functions instead.

Edit: Note that instead of excluding the None policy completely, you might want to restrict it for discovery only, by setting config->securityPolicyNoneDiscoveryOnly = true;.

growgreat77 commented 1 year ago

Encryption and AccessControl are different things. The Encryption setup and the certificates take care of the encryption of the connection, AccessControl controls what the user can do with an established connection (encrypted or unencrypted).

AccessControl is realized as a plug in that you have to set up yourself to reflect the internal user/permission management of your application. Take a look at the examples/access_control folder to get an idea.

As for the unencrypted connection, you are using UA_ServerConfig_setDefaultWithSecurityPolicies() which includes the None security policy which allows connection without encryption. If you want to prevent that, you have to add the desired security policies manually with the UA_ServerConfig_addSecurityPolicy*() functions instead.

Edit: Note that instead of excluding the None policy completely, you might want to restrict it for discovery only, by setting config->securityPolicyNoneDiscoveryOnly = true;.

Thank you for helping me. My main goal is only to allow connection with encryption, so I modified the code. my updated code is :

    UA_StatusCode retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &certificate, &privateKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                       UA_StatusCode_name(retval));
    }

but the prompts is still no encrypting SecurityPolicy:

Username/Password Authentication configured, but no encrypting SecurityPolicy. This can leak credentials on the network.

Furthermore, I can still connect to this server without any encryption or anonymously useing this client :https://industrial.softing.com/products/opc-ua-and-opc-classic-sdks/opc-ua-demo-client.ht.

neojaw commented 1 year ago

Do you still have the UA_ServerConfig_setDefaultWithSecurityPolicies() call? Because that log line comes from UA_AccessControl_default() which is called from there and I don't see you doing it explicitly. This would also explain the unencrypted connection.

growgreat77 commented 1 year ago

Do you still have the UA_ServerConfig_setDefaultWithSecurityPolicies() call? Because that log line comes from UA_AccessControl_default() which is called from there and I don't see you doing it explicitly. This would also explain the unencrypted connection.

I add the desired security policies manually with the UA_ServerConfig_addSecurityPolicy*() functions instead of UA_ServerConfig_setDefaultWithSecurityPolicies()

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *
 */

#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>
#include <open62541/plugin/create_certificate.h>
#include <open62541/plugin/securitypolicy.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>

#include <signal.h>
#include <stdlib.h>

#include "common.h"

UA_Boolean running = true;
static void stopHandler(int sig) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
    running = false;
}

int main(int argc, char* argv[]) {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);
    UA_ByteString certificate = UA_BYTESTRING_NULL;
    UA_ByteString privateKey = UA_BYTESTRING_NULL;
    if(argc >= 3) {
        /* Load certificate and private key */
        certificate = loadFile(argv[1]);
        privateKey = loadFile(argv[2]);
    } else {
        UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "Missing arguments. Arguments are "
                     "<server-certificate.der> <private-key.der> "
                     "[<trustlist1.crl>, ...]");
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                    "Trying to create a certificate.");
        UA_String subject[3] = {UA_STRING_STATIC("C=DE"),
                            UA_STRING_STATIC("O=SampleOrganization"),
                            UA_STRING_STATIC("CN=Open62541Server@localhost")};
        UA_UInt32 lenSubject = 3;
        UA_String subjectAltName[2]= {
            UA_STRING_STATIC("DNS:localhost"),
            UA_STRING_STATIC("URI:urn:open62541.server.application")
        };
        UA_UInt32 lenSubjectAltName = 2;
        UA_StatusCode statusCertGen =
            UA_CreateCertificate(UA_Log_Stdout,
                                 subject, lenSubject,
                                 subjectAltName, lenSubjectAltName,
                                 0, UA_CERTIFICATEFORMAT_DER,
                                 &privateKey, &certificate);

        if(statusCertGen != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                "Generating Certificate failed: %s",
                UA_StatusCode_name(statusCertGen));
            return EXIT_SUCCESS;
        }
#else
        return EXIT_SUCCESS;
#endif
    }

    /* Load the trustlist */
    size_t trustListSize = 0;
    if(argc > 3)
        trustListSize = (size_t)argc-3;
    UA_STACKARRAY(UA_ByteString, trustList, trustListSize+1);
    for(size_t i = 0; i < trustListSize; i++)
        trustList[i] = loadFile(argv[i+3]);

    /* Loading of an issuer list, not used in this application */
    size_t issuerListSize = 0;
    UA_ByteString *issuerList = NULL;

    /* Loading of a revocation list currently unsupported */
    UA_ByteString *revocationList = NULL;
    size_t revocationListSize = 0;

    UA_Server *server = UA_Server_new();
    UA_ServerConfig *config = UA_Server_getConfig(server);

    UA_StatusCode retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &certificate, &privateKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(&config->logger, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    // UA_StatusCode retval =
    //     UA_ServerConfig_setDefaultWithSecurityPolicies(config, 4840,
    //                                                    &certificate, &privateKey,
    //                                                    trustList, trustListSize,
    //                                                    issuerList, issuerListSize,
    //                                                    revocationList, revocationListSize);

    #ifdef UA_ENABLE_WEBSOCKET_SERVER
    UA_ServerConfig_addNetworkLayerWS(UA_Server_getConfig(server), 7681, 0, 0, &certificate, &privateKey);
    #endif

    UA_ByteString_clear(&certificate);
    UA_ByteString_clear(&privateKey);
    for(size_t i = 0; i < trustListSize; i++)
        UA_ByteString_clear(&trustList[i]);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    if(!running)
        goto cleanup; /* received ctrl-c already */

    retval = UA_Server_run(server, &running);

 cleanup:
    UA_Server_delete(server);
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
neojaw commented 1 year ago

Did you recompile? Because that code does not even run on my machine since there is no CertificateVerification set up.

UA_CertificateVerification_Trustlist(&config->certificateVerification, trustList, trustListSize, issuerList, issuerListSize, revocationList, revocationListSize);
growgreat77 commented 1 year ago

Did you recompile? Because that code does not even run on my machine since there is no CertificateVerification set up.

UA_CertificateVerification_Trustlist(&config->certificateVerification, trustList, trustListSize, issuerList, issuerListSize, revocationList, revocationListSize);

Did you put the common.h in directory or generate key? I deleted all the previously compiled files and then made some modifications to the function UA_ServerConfig_addSecurityPolicyBasic256Sha256 you mentioned. Then I went to the build directory, ran "cmake .. && make". Here is my modified CMakeLists.txt code:

cmake_minimum_required(VERSION 3.5)

project(OPCUA1)

set (EXECUTABLE_OUTPUT_PATH  ${PROJECT_SOURCE_DIR}/bin)

add_definitions(-std=c99)

include_directories(${PROJECT_SOURCE_DIR}/open62541)
include_directories(${PROJECT_SOURCE_DIR}/src)

find_package(OpenSSL REQUIRED)

add_executable(server ${PROJECT_SOURCE_DIR}/src/server.c ${PROJECT_SOURCE_DIR}/open62541/open62541.c)
target_link_libraries(server ${OPENSSL_LIBRARIES})

add_executable(client ${PROJECT_SOURCE_DIR}/src/client.c ${PROJECT_SOURCE_DIR}/open62541/open62541.c)
target_link_libraries(client ${OPENSSL_LIBRARIES})
neojaw commented 1 year ago

Sure I did that and it compiles just fine, but it crashes once I run it. Gdb then shows me that the server->config.certificateVerification object is full of null pointers which makes sense because it is not set up. I don't see how this could be different for you.

growgreat77 commented 1 year ago

Encryption

everythin is going well in my tutorials, except the Encryption. I get the code with git clone.