소스 검색

add securitypolicy plugin API and implementation for #none

Infinity95 6 년 전
부모
커밋
952bd5ebef

+ 12 - 4
CMakeLists.txt

@@ -259,8 +259,13 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_plugin_nodestore.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
-                     ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h)
-
+                     ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
+                     ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.h
+                     ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.h
+                     ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.h
+                     ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.h
+                     ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.h
+)
 set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
                      ${PROJECT_SOURCE_DIR}/deps/libc_time.h
@@ -318,6 +323,7 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_discovery.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel_subscriptions.c
+
                 # dependencies
                 ${PROJECT_SOURCE_DIR}/deps/libc_time.c
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
@@ -326,14 +332,16 @@ set(default_plugin_headers ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.h
                            ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.h
                            ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.h
                            ${PROJECT_SOURCE_DIR}/plugins/ua_nodestore_default.h
-                           ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.h)
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.h
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.h)
 
 set(default_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_clock.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_nodestore_default.c
-                           ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.c)
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.c
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.c)
 
 if(UA_DEBUG_DUMP_PKGS)
     list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/plugins/ua_debug_dump_pkgs.c)

+ 286 - 38
include/ua_plugin_securitypolicy.h

@@ -1,38 +1,286 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef UA_PLUGIN_SECURITYPOLICY_H_
-#define UA_PLUGIN_SECURITYPOLICY_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "ua_types.h"
-#include "ua_plugin_log.h"
-#include "ua_types_generated.h"
-
-extern const UA_ByteString UA_SECURITY_POLICY_NONE_URI;
-
-struct UA_SecurityPolicy;
-typedef struct UA_SecurityPolicy UA_SecurityPolicy;
-
-/* Holds an endpoint description and the corresponding security policy
- * Also holds the context for the endpoint. */
-typedef struct {
-    UA_SecurityPolicy *securityPolicy;
-    void *securityContext;
-    UA_EndpointDescription endpointDescription;
-} UA_Endpoint;
-
-typedef struct {
-    size_t count;
-    UA_Endpoint *endpoints;
-} UA_Endpoints;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* UA_PLUGIN_SECURITYPOLICY_H_ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UA_PLUGIN_SECURITYPOLICY_H_
+#define UA_PLUGIN_SECURITYPOLICY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_types.h"
+#include "ua_types_generated.h"
+
+extern const UA_ByteString UA_SECURITY_POLICY_NONE_URI;
+
+struct UA_SecurityPolicy;
+typedef struct UA_SecurityPolicy UA_SecurityPolicy;
+
+typedef struct {
+    /* Verifies the signature of the message using the provided keys in the context.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext that contains the key to verify
+     *                       the supplied message with.
+     * @param message the message to which the signature is supposed to belong.
+     * @param signature the signature of the message, that should be verified. */
+    UA_StatusCode (*verify)(const UA_SecurityPolicy *securityPolicy,
+                            const void *channelContext,
+                            const UA_ByteString *message,
+                            const UA_ByteString *signature);
+
+    /* Signs the given message using this policys signing algorithm and the
+     * provided keys in the context.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext that contains the key to sign
+     *                       the supplied message with.
+     * @param message the message to sign.
+     * @param signature an output buffer to which the signature is written. The
+     *                  buffer needs to be allocated by the caller. The
+     *                  necessary size can be acquired with the signatureSize
+     *                  attribute of this module. */
+    UA_StatusCode (*sign)(const UA_SecurityPolicy *securityPolicy,
+                          const void *channelContext,
+                          const UA_ByteString *message,
+                          UA_ByteString *signature);
+
+    /* Gets the signature size that depends on the local private key.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext that contains the
+     *                       certificate/key.
+     * @return the size of the local signature. Returns 0 if no local
+     *         certificate was set. */
+    size_t (*getLocalSignatureSize)(const UA_SecurityPolicy *securityPolicy,
+                                    const void *channelContext);
+
+    /* Gets the signature size that depends on the remote public key.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the context to retrieve data from.
+     * @return the size of the remote asymmetric signature. Returns 0 if no
+     *         remote certificate was set previousely. */
+    size_t (*getRemoteSignatureSize)(const UA_SecurityPolicy *securityPolicy,
+                                     const void *channelContext);
+
+    /* The signature size in bytes */
+    UA_String signatureAlgorithmUri;
+} UA_SecurityPolicySigningModule;
+
+typedef struct {
+    /* Encrypt the given data in place using an asymmetric algorithm and keys.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext which contains information about
+     *                       the keys to encrypt data.
+     * @param data the data that is encrypted. The encrypted data will overwrite
+     *             the data that was supplied. */
+    UA_StatusCode(*encrypt)(const UA_SecurityPolicy *securityPolicy,
+                            const void *channelContext,
+                            UA_ByteString *data);
+    /* Decrypts the given ciphertext in place using an asymmetric algorithm and
+     * key.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext which contains information about
+     *                       the keys needed to decrypt the message.
+     * @param data the data to decrypt. The decryption is done in place. */
+    UA_StatusCode(*decrypt)(const UA_SecurityPolicy *securityPolicy,
+                            const void *channelContext,
+                            UA_ByteString *data);
+} UA_SecurityPolicyEncryptingModule;
+
+typedef struct {
+    /* Generates a thumprint for the specified certificate.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param certificate the certificate to make a thumbprint of.
+     * @param thumbprint an output buffer for the resulting thumbprint. Always
+     *                   has the length specified in the thumprintLenght in the
+     *                   asymmetricModule. */
+    UA_StatusCode (*makeCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy,
+                                               const UA_ByteString *certificate,
+                                               UA_ByteString *thumbprint);
+
+    /* Compares the supplied certificate with the certificate in the endpoit context.
+     *
+     * @param securityPolicy the policy data that contains the certificate
+     *                       to compare to.
+     * @param certificateThumbprint the certificate thumbprint to compare to the
+     *                              one stored in the context.
+     * @return if the thumbprints match UA_STATUSCODE_GOOD is returned. If they
+     *         don't match or an error occured an error code is returned. */
+    UA_StatusCode (*compareCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy,
+                                                  const UA_ByteString *certificateThumbprint);
+
+    size_t minAsymmetricKeyLength;
+    size_t maxAsymmetricKeyLength;
+    size_t thumbprintLength;
+
+    UA_SecurityPolicyEncryptingModule encryptingModule;
+    UA_SecurityPolicySigningModule signingModule;
+} UA_SecurityPolicyAsymmetricModule;
+
+typedef struct {
+    /* Pseudo random function that is used to generate the symmetric keys.
+     *
+     * For information on what parameters this function receives in what situation,
+     * refer to the OPC UA specification 1.03 Part6 Table 33
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param secret
+     * @param seed
+     * @param out an output to write the data to. The length defines the maximum
+     *            number of output bytes that are produced. */
+    UA_StatusCode (*generateKey)(const UA_SecurityPolicy *securityPolicy,
+                                 const UA_ByteString *secret,
+                                 const UA_ByteString *seed,
+                                       UA_ByteString *out);
+    /* Random generator for generating nonces.
+     *
+     * @param securityPolicy the securityPolicy this function is invoked on.
+     *                       Example: myPolicy->generateNonce(myPolicy,
+     *                       &outBuff);
+     * @param out pointer to a buffer to store the nonce in. Needs to be
+     *            allocated by the caller. The buffer is filled with random
+     *            data. */
+    UA_StatusCode (*generateNonce)(const UA_SecurityPolicy *securityPolicy,
+                                   UA_ByteString *out);
+
+    UA_SecurityPolicyEncryptingModule encryptingModule;
+    UA_SecurityPolicySigningModule signingModule;
+
+    size_t signingKeyLength;
+    size_t encryptingKeyLength;
+    size_t encryptingBlockSize;
+} UA_SecurityPolicySymmetricModule;
+
+typedef struct {
+    /* This method creates a new context data object.
+     *
+     * The caller needs to call delete on the recieved object to free allocated
+     * memory. Memory is only allocated if the function succeeds so there is no
+     * need to manually free the memory pointed to by *channelContext or to
+     * call delete in case of failure.
+     *
+     * @param securityPolicy the policy context of the endpoint that is connected
+     *                       to. It will be stored in the channelContext for
+     *                       further access by the policy.
+     * @param remoteCertificate the remote certificate contains the remote
+     *                          asymmetric key. The certificate will be verified
+     *                          and then stored in the context so that its
+     *                          details may be accessed.
+     * @param channelContext the initialized channelContext that is passed to
+     *                       functions that work on a context. */
+    UA_StatusCode (*newContext)(const UA_SecurityPolicy *securityPolicy,
+                                const UA_ByteString *remoteCertificate,
+                                void **channelContext);
+
+    /* Deletes the the security context. */
+    void (*deleteContext)(void *channelContext);
+
+    /* Sets the local encrypting key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the local encrypting key to store in the context. */
+    UA_StatusCode (*setLocalSymEncryptingKey)(void *channelContext,
+                                              const UA_ByteString *key);
+
+    /* Sets the local signing key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the local signing key to store in the context. */
+    UA_StatusCode (*setLocalSymSigningKey)(void *channelContext,
+                                           const UA_ByteString *key);
+
+    /* Sets the local initialization vector in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param iv the local initialization vector to store in the context. */
+    UA_StatusCode (*setLocalSymIv)(void *channelContext,
+                                   const UA_ByteString *iv);
+    /* Sets the remote encrypting key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the remote encrypting key to store in the context. */
+    UA_StatusCode (*setRemoteSymEncryptingKey)(void *channelContext,
+                                               const UA_ByteString *key);
+
+    /* Sets the remote signing key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the remote signing key to store in the context. */
+    UA_StatusCode (*setRemoteSymSigningKey)(void *channelContext,
+                                            const UA_ByteString *key);
+
+    /* Sets the remote initialization vector in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param iv the remote initialization vector to store in the context. */
+    UA_StatusCode (*setRemoteSymIv)(void *channelContext,
+                                    const UA_ByteString *iv);
+
+    /* Compares the supplied certificate with the certificate in the channel
+     * context.
+     *
+     * @param channelContext the channel context data that contains the
+     *                       certificate to compare to.
+     * @param certificate the certificate to compare to the one stored in the context.
+     * @return if the certificates match UA_STATUSCODE_GOOD is returned. If they
+     *         don't match or an errror occured an error code is returned. */
+    UA_StatusCode (*compareCertificate)(const void *channelContext,
+                                        const UA_ByteString *certificate);
+
+    /* Gets the plaintext block size that depends on the remote public key.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the size of the plain text block size when encrypting with the
+     *         remote public key. Returns 0 as long as no remote certificate was
+     *         set previousely. */
+    size_t (*getRemoteAsymPlainTextBlockSize)(const void *channelContext);
+
+    /* Gets the number of bytes that are needed by the encryption function in
+     * addition to the length of the plaintext message. This is needed, since
+     * most rsa encryption methods have their own padding mechanism included.
+     * This makes the encrypted message larger than the plainText, so we need to
+     * have enough room in the buffer for the overhead.
+     *
+     * @param channelContext the retrieve data from.
+     * @param maxEncryptionLength the maximum number of bytes that the data to
+     *                            encrypt can be. */
+    size_t (*getRemoteAsymEncryptionBufferLengthOverhead)(const void *channelContext,
+                                                          size_t maxEncryptionLength);
+} UA_SecurityPolicyChannelModule;
+
+struct UA_SecurityPolicy {
+    /* Additional data */
+    void *policyContext;
+
+    /* The policy uri that identifies the implemented algorithms */
+    UA_ByteString policyUri;
+
+    /* The local certificate is specific for each SecurityPolicy since it
+     * depends on the used key length. */
+    UA_ByteString localCertificate;
+
+    /* Function pointers grouped into modules */
+    UA_SecurityPolicyAsymmetricModule asymmetricModule;
+    UA_SecurityPolicySymmetricModule symmetricModule;
+    UA_SecurityPolicyChannelModule channelModule;
+
+    /* Deletes the dynamic content of the policy */
+    void (*deleteMembers)(UA_SecurityPolicy *policy);
+};
+
+typedef struct {
+    UA_SecurityPolicy securityPolicy;
+    UA_EndpointDescription endpointDescription;
+} UA_Endpoint;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_PLUGIN_SECURITYPOLICY_H_ */

+ 2 - 1
include/ua_server_config.h

@@ -57,7 +57,8 @@ struct UA_ServerConfig {
     UA_ServerNetworkLayer *networkLayers;
 
     /* Available endpoints */
-    UA_Endpoints endpoints;
+    size_t endpointsSize;
+    UA_Endpoint *endpoints;
 
     /* Global Node Lifecycle */
     UA_GlobalNodeLifecycle nodeLifecycle;

+ 31 - 21
plugins/ua_config_default.c

@@ -6,6 +6,11 @@
 #include "ua_network_tcp.h"
 #include "ua_accesscontrol_default.h"
 #include "ua_nodestore_default.h"
+#include "ua_types_generated.h"
+#include "ua_securitypolicy_none.h"
+#include "ua_types.h"
+#include "ua_types_generated_handling.h"
+#include "ua_client_highlevel.h"
 
 #define ANONYMOUS_POLICY "open62541-anonymous-policy"
 #define USERNAME_POLICY "open62541-username-policy"
@@ -53,10 +58,10 @@ const UA_ConnectionConfig UA_ConnectionConfig_default = {
 
 static UA_StatusCode
 createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint,
-                                 const UA_ByteString *cert) {
+                                 const UA_ByteString localCertificate) {
     UA_EndpointDescription_init(&endpoint->endpointDescription);
 
-    endpoint->securityPolicy = NULL;
+    UA_SecurityPolicy_None(&endpoint->securityPolicy, localCertificate, conf->logger);
     endpoint->endpointDescription.securityMode = UA_MESSAGESECURITYMODE_NONE;
     endpoint->endpointDescription.securityPolicyUri =
         UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
@@ -81,8 +86,7 @@ createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint,
     endpoint->endpointDescription.userIdentityTokens[1].policyId =
         UA_STRING_ALLOC(USERNAME_POLICY);
 
-    if(cert)
-        UA_String_copy(cert, &endpoint->endpointDescription.serverCertificate);
+    UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
 
     UA_ApplicationDescription_copy(&conf->applicationDescription,
                                    &endpoint->endpointDescription.server);
@@ -202,16 +206,19 @@ UA_ServerConfig_new_minimal(UA_UInt16 portNumber,
     conf->networkLayersSize = 1;
 
     /* Allocate the endpoint */
-    conf->endpoints.endpoints = (UA_Endpoint*)UA_malloc(sizeof(UA_Endpoint));
-    if(!conf->endpoints.endpoints) {
+    conf->endpointsSize = 1;
+    conf->endpoints = (UA_Endpoint*)UA_malloc(sizeof(UA_Endpoint));
+    if(!conf->endpoints) {
         UA_ServerConfig_delete(conf);
         return NULL;
     }
-    conf->endpoints.count = 1;
 
     /* Populate the endpoint */
-    retval = createSecurityPolicyNoneEndpoint(conf, &conf->endpoints.endpoints[0],
-                                              certificate);
+    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
+    if(certificate)
+        localCertificate = *certificate;
+    UA_StatusCode retval =
+        createSecurityPolicyNoneEndpoint(conf, &conf->endpoints[0], localCertificate);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_ServerConfig_delete(conf);
         return NULL;
@@ -232,8 +239,8 @@ UA_ServerConfig_delete(UA_ServerConfig *config) {
     UA_String_deleteMembers(&config->mdnsServerName);
     UA_Array_delete(config->serverCapabilities, config->serverCapabilitiesSize,
                     &UA_TYPES[UA_TYPES_STRING]);
-    /* config->serverCapabilities = NULL; */
-    /* config->serverCapabilitiesSize = 0; */
+    config->serverCapabilities = NULL;
+    config->serverCapabilitiesSize = 0;
 #endif
 
     /* Nodestore */
@@ -244,21 +251,24 @@ UA_ServerConfig_delete(UA_ServerConfig *config) {
     for(size_t i = 0; i < config->customDataTypesSize; ++i)
         UA_free(config->customDataTypes[i].members);
     UA_free(config->customDataTypes);
-    /* config->customDataTypes = NULL; */
-    /* config0>customDataTypesSize = 0; */
+    config->customDataTypes = NULL;
+    config->customDataTypesSize = 0;
 
     /* Networking */
     for(size_t i = 0; i < config->networkLayersSize; ++i)
         config->networkLayers[i].deleteMembers(&config->networkLayers[i]);
     UA_free(config->networkLayers);
-    /* config->networkLayers = NULL; */
-    /* config->networkLayersSize = 0; */
-
-    for(size_t i = 0; i < config->endpoints.count; ++i)
-        UA_EndpointDescription_deleteMembers(&config->endpoints.endpoints[i].endpointDescription);
-    UA_free(config->endpoints.endpoints);
-    /* config->endpoints.endpoints = NULL; */
-    /* config->endpoints.count = 0; */
+    config->networkLayers = NULL;
+    config->networkLayersSize = 0;
+
+    for(size_t i = 0; i < config->endpointsSize; ++i) {
+        UA_SecurityPolicy *policy = &config->endpoints[i].securityPolicy;
+        policy->deleteMembers(policy);
+        UA_EndpointDescription_deleteMembers(&config->endpoints[i].endpointDescription);
+    }
+    UA_free(config->endpoints);
+    config->endpoints = NULL;
+    config->endpointsSize = 0;
 
     UA_free(config);
 }

+ 0 - 1
plugins/ua_config_default.h

@@ -11,7 +11,6 @@ extern "C" {
 #include "ua_server.h"
 #include "ua_server_config.h"
 #include "ua_client.h"
-#include "ua_client_highlevel.h"
 
 /**********************/
 /* Default Connection */

+ 304 - 0
plugins/ua_securitypolicy_none.c

@@ -0,0 +1,304 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include "ua_securitypolicy_none.h"
+#include "ua_types_generated_handling.h"
+
+/*******************************/
+/* Asymmetric module functions */
+/*******************************/
+
+static UA_StatusCode
+asym_verify_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                    const void *const channelContext,
+                    const UA_ByteString *const message,
+                    const UA_ByteString *const signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+asym_sign_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                  const void *const channelContext,
+                  const UA_ByteString *const message,
+                  UA_ByteString *const signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+asym_getLocalSignatureSize_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                                   const void *const channelContext) {
+    return 0;
+}
+
+static size_t
+asym_getRemoteSignatureSize_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                                    const void *const channelContext) {
+    return 0;
+}
+
+static UA_StatusCode
+asym_encrypt_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                     const void *const channelContext,
+                     UA_ByteString *const data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+asym_decrypt_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                     const void *const channelContext,
+                     UA_ByteString *const data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+asym_makeThumbprint_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                            const UA_ByteString *const certificate,
+                            UA_ByteString *const thumbprint) {
+    if(certificate == NULL || thumbprint == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    return UA_STATUSCODE_GOOD;
+}
+
+/* Only a stub function for now */
+static UA_StatusCode
+asym_compareThumbprint_sp_none(const UA_SecurityPolicy *securityPolicy,
+                               const UA_ByteString *certificateThumbprint) {
+    if(!securityPolicy || !certificateThumbprint)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    // The certificatethumbprint doesn't exist if the security policy is none
+    if(certificateThumbprint->length != 0)
+        return UA_STATUSCODE_BADCERTIFICATEINVALID;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+/******************************/
+/* Symmetric module functions */
+/******************************/
+
+static UA_StatusCode
+sym_verify_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                   const void *const channelContext,
+                   const UA_ByteString *const message,
+                   const UA_ByteString *const signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sym_sign_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                 const void *const channelContext,
+                 const UA_ByteString *const message,
+                 UA_ByteString *const signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+sym_getLocalSignatureSize_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                                  const void *const channelContext) {
+    return 0;
+}
+
+static size_t
+sym_getRemoteSignatureSize_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                                   const void *const channelContext) {
+    return 0;
+}
+
+static UA_StatusCode
+sym_encrypt_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                    const void *const channelContext,
+                    UA_ByteString *const data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sym_decrypt_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                    const void *const channelContext,
+                    UA_ByteString *const data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sym_generateKey_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                        const UA_ByteString *const secret,
+                        const UA_ByteString *const seed,
+                        UA_ByteString *const out) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sym_generateNonce_sp_none(const UA_SecurityPolicy *const securityPolicy,
+                          UA_ByteString *const out) {
+    out->length = securityPolicy->symmetricModule.encryptingKeyLength;
+    out->data[0] = 'a';
+    return UA_STATUSCODE_GOOD;
+}
+
+/***************************/
+/* ChannelModule functions */
+/***************************/
+
+// this is not really needed in security policy none because no context is required
+// it is there to serve as a small example for policies that need context per channel
+typedef struct {
+    const UA_SecurityPolicy *securityPolicy;
+    int callCounter;
+} UA_SP_NONE_ChannelContextData;
+
+static UA_StatusCode
+channelContext_newContext_sp_none(const UA_SecurityPolicy *securityPolicy,
+                                  const UA_ByteString *remoteCertificate,
+                                  void **channelContext) {
+    if(channelContext == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    *channelContext = UA_malloc(sizeof(UA_SP_NONE_ChannelContextData));
+    if(*channelContext == NULL)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    // Initialize the channelcontext data here to sensible values
+    UA_SP_NONE_ChannelContextData* const data = (UA_SP_NONE_ChannelContextData*)*channelContext;
+
+    data->callCounter = 0;
+    data->securityPolicy = securityPolicy;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+channelContext_deleteContext_sp_none(void *const channelContext) {
+    if(channelContext != NULL)
+        UA_free(channelContext);
+}
+
+static UA_StatusCode
+channelContext_setLocalSymEncryptingKey_sp_none(void *const channelContext,
+                                                const UA_ByteString *const key) {
+    UA_SP_NONE_ChannelContextData* const data = (UA_SP_NONE_ChannelContextData*)channelContext;
+    data->callCounter++;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+channelContext_setLocalSymSigningKey_sp_none(void *const channelContext,
+                                             const UA_ByteString *const key) {
+    UA_SP_NONE_ChannelContextData* const data = (UA_SP_NONE_ChannelContextData*)channelContext;
+    data->callCounter++;
+    return UA_STATUSCODE_GOOD;
+}
+
+
+static UA_StatusCode
+channelContext_setLocalSymIv_sp_none(void *const channelContext,
+                                     const UA_ByteString *const iv) {
+    UA_SP_NONE_ChannelContextData* const data = (UA_SP_NONE_ChannelContextData*)channelContext;
+    data->callCounter++;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymEncryptingKey_sp_none(void *const channelContext,
+                                                 const UA_ByteString *const key) {
+    UA_SP_NONE_ChannelContextData* const data = (UA_SP_NONE_ChannelContextData*)channelContext;
+    data->callCounter++;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymSigningKey_sp_none(void *const channelContext,
+                                              const UA_ByteString *const key) {
+    UA_SP_NONE_ChannelContextData* const data = (UA_SP_NONE_ChannelContextData*)channelContext;
+    data->callCounter++;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+channelContext_setRemoteSymIv_sp_none(void *const channelContext,
+                                      const UA_ByteString *const iv) {
+    UA_SP_NONE_ChannelContextData* const data = (UA_SP_NONE_ChannelContextData*)channelContext;
+    data->callCounter++;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+channelContext_compareCertificate_sp_none(const void *const channelContext,
+                                          const UA_ByteString *const certificate) {
+    if(channelContext == NULL || certificate == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+channelContext_getRemoteAsymPlainTextBlockSize_sp_none(const void *const channelContext) {
+    return 0;
+}
+
+static size_t
+channelContext_getRemoteAsymEncryptionBufferLengthOverhead_sp_none(const void *const channelContext,
+                                                                   const size_t maxEncryptionLength) {
+    return 0;
+}
+
+/*****************************/
+/* Security Policy functions */
+/*****************************/
+
+static void
+policy_deletemembers_sp_none(UA_SecurityPolicy *policy) {
+    UA_ByteString_deleteMembers(&policy->localCertificate);
+}
+
+UA_StatusCode
+UA_SecurityPolicy_None(UA_SecurityPolicy *policy,
+                       const UA_ByteString localCertificate,
+                       UA_Logger logger) {
+    policy->policyContext = (void*)(uintptr_t)logger;
+    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
+    UA_ByteString_copy(&localCertificate, &policy->localCertificate);
+
+    policy->asymmetricModule.makeCertificateThumbprint = asym_makeThumbprint_sp_none;
+    policy->asymmetricModule.compareCertificateThumbprint = asym_compareThumbprint_sp_none;
+    policy->asymmetricModule.minAsymmetricKeyLength = 0;
+    policy->asymmetricModule.maxAsymmetricKeyLength = 0;
+    policy->asymmetricModule.thumbprintLength = 20;
+    policy->asymmetricModule.encryptingModule.encrypt = asym_encrypt_sp_none;
+    policy->asymmetricModule.encryptingModule.decrypt = asym_decrypt_sp_none;
+    policy->asymmetricModule.signingModule.verify = asym_verify_sp_none;
+    policy->asymmetricModule.signingModule.sign = asym_sign_sp_none;
+    policy->asymmetricModule.signingModule.getLocalSignatureSize = asym_getLocalSignatureSize_sp_none;
+    policy->asymmetricModule.signingModule.getRemoteSignatureSize = asym_getRemoteSignatureSize_sp_none;
+    policy->asymmetricModule.signingModule.signatureAlgorithmUri = UA_STRING_NULL;
+
+    policy->symmetricModule.generateKey = sym_generateKey_sp_none;
+    policy->symmetricModule.generateNonce = sym_generateNonce_sp_none;
+    policy->symmetricModule.encryptingModule.encrypt = sym_encrypt_sp_none;
+    policy->symmetricModule.encryptingModule.decrypt = sym_decrypt_sp_none;
+    policy->symmetricModule.signingModule.verify = sym_verify_sp_none;
+    policy->symmetricModule.signingModule.sign = sym_sign_sp_none;
+    policy->symmetricModule.signingModule.getLocalSignatureSize = sym_getLocalSignatureSize_sp_none;
+    policy->symmetricModule.signingModule.getRemoteSignatureSize = sym_getRemoteSignatureSize_sp_none;
+    policy->symmetricModule.signingModule.signatureAlgorithmUri = UA_STRING_NULL;
+    policy->symmetricModule.signingKeyLength = 0;
+    policy->symmetricModule.encryptingKeyLength = 1;
+    policy->symmetricModule.encryptingBlockSize = 0;
+
+    policy->channelModule.newContext = channelContext_newContext_sp_none;
+    policy->channelModule.deleteContext = channelContext_deleteContext_sp_none;
+    policy->channelModule.setLocalSymEncryptingKey = channelContext_setLocalSymEncryptingKey_sp_none;
+    policy->channelModule.setLocalSymSigningKey = channelContext_setLocalSymSigningKey_sp_none;
+    policy->channelModule.setLocalSymIv = channelContext_setLocalSymIv_sp_none;
+    policy->channelModule.setRemoteSymEncryptingKey = channelContext_setRemoteSymEncryptingKey_sp_none;
+    policy->channelModule.setRemoteSymSigningKey = channelContext_setRemoteSymSigningKey_sp_none;
+    policy->channelModule.setRemoteSymIv = channelContext_setRemoteSymIv_sp_none;
+    policy->channelModule.compareCertificate = channelContext_compareCertificate_sp_none;
+    policy->channelModule.getRemoteAsymPlainTextBlockSize =
+        channelContext_getRemoteAsymPlainTextBlockSize_sp_none;
+    policy->channelModule.getRemoteAsymEncryptionBufferLengthOverhead =
+        channelContext_getRemoteAsymEncryptionBufferLengthOverhead_sp_none;
+
+    policy->deleteMembers = policy_deletemembers_sp_none;
+
+    return UA_STATUSCODE_GOOD;
+}

+ 22 - 0
plugins/ua_securitypolicy_none.h

@@ -0,0 +1,22 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#ifndef UA_SECURITYPOLICY_NONE_H_
+#define UA_SECURITYPOLICY_NONE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_plugin_securitypolicy.h"
+#include "ua_plugin_log.h"
+
+UA_StatusCode UA_EXPORT
+UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
+                       UA_Logger logger);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_SECURITYPOLICY_NONE_H_ */

+ 1 - 1
src/server/ua_server.c

@@ -161,7 +161,7 @@ UA_Server_new(const UA_ServerConfig *config) {
     if(!server)
         return NULL;
 
-    if(config->endpoints.count == 0) {
+    if(config->endpointsSize == 0) {
         UA_LOG_FATAL(config->logger,
                      UA_LOGCATEGORY_SERVER,
                      "There has to be at least one endpoint.");

+ 8 - 8
src/server/ua_services_discovery.c

@@ -246,19 +246,19 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
     }
 
     /* test if the supported binary profile shall be returned */
-    size_t reSize = sizeof(UA_Boolean) * server->config.endpoints.count;
+    size_t reSize = sizeof(UA_Boolean) * server->config.endpointsSize;
     UA_Boolean *relevant_endpoints = (UA_Boolean *)UA_alloca(reSize);
-    memset(relevant_endpoints, 0, sizeof(UA_Boolean) * server->config.endpoints.count);
+    memset(relevant_endpoints, 0, sizeof(UA_Boolean) * server->config.endpointsSize);
     size_t relevant_count = 0;
     if(request->profileUrisSize == 0) {
-        for(size_t j = 0; j < server->config.endpoints.count; ++j)
+        for(size_t j = 0; j < server->config.endpointsSize; ++j)
             relevant_endpoints[j] = true;
-        relevant_count = server->config.endpoints.count;
+        relevant_count = server->config.endpointsSize;
     } else {
-        for(size_t j = 0; j < server->config.endpoints.count; ++j) {
+        for(size_t j = 0; j < server->config.endpointsSize; ++j) {
             for(size_t i = 0; i < request->profileUrisSize; ++i) {
                 if(!UA_String_equal(&request->profileUris[i],
-                                    &server->config.endpoints.endpoints[j].endpointDescription.transportProfileUri))
+                                    &server->config.endpoints[j].endpointDescription.transportProfileUri))
                     continue;
                 relevant_endpoints[j] = true;
                 ++relevant_count;
@@ -294,10 +294,10 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
     for(size_t i = 0; i < clone_times; ++i) {
         if(nl_endpointurl)
             endpointUrl = &server->config.networkLayers[i].discoveryUrl;
-        for(size_t j = 0; j < server->config.endpoints.count; ++j) {
+        for(size_t j = 0; j < server->config.endpointsSize; ++j) {
             if(!relevant_endpoints[j])
                 continue;
-            retval |= UA_EndpointDescription_copy(&server->config.endpoints.endpoints[j].endpointDescription,
+            retval |= UA_EndpointDescription_copy(&server->config.endpoints[j].endpointDescription,
                                                   &response->endpoints[k]);
             retval |= UA_String_copy(endpointUrl, &response->endpoints[k].endpointUrl);
             ++k;

+ 6 - 6
src/server/ua_services_session.c

@@ -18,18 +18,18 @@ void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
 
     /* Allocate the response */
     response->serverEndpoints = (UA_EndpointDescription*)
-        UA_Array_new(server->config.endpoints.count,
+        UA_Array_new(server->config.endpointsSize,
                      &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
     if(!response->serverEndpoints) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
-    response->serverEndpointsSize = server->config.endpoints.count;
+    response->serverEndpointsSize = server->config.endpointsSize;
 
     /* Copy the server's endpointdescriptions into the response */
-    for(size_t i = 0; i < server->config.endpoints.count; ++i)
+    for(size_t i = 0; i < server->config.endpointsSize; ++i)
         response->responseHeader.serviceResult |=
-            UA_EndpointDescription_copy(&server->config.endpoints.endpoints[0].endpointDescription,
+            UA_EndpointDescription_copy(&server->config.endpoints[0].endpointDescription,
                                         &response->serverEndpoints[i]);
 
     /* Mirror back the endpointUrl */
@@ -63,9 +63,9 @@ void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
     response->authenticationToken = newSession->authenticationToken;
     response->responseHeader.serviceResult =
         UA_String_copy(&request->sessionName, &newSession->sessionName);
-    if(server->config.endpoints.count > 0)
+    if(server->config.endpointsSize > 0)
         response->responseHeader.serviceResult |=
-            UA_ByteString_copy(&server->config.endpoints.endpoints[0].endpointDescription.serverCertificate,
+            UA_ByteString_copy(&server->config.endpoints[0].endpointDescription.serverCertificate,
                                &response->serverCertificate);
 
     /* Failure -> remove the session */

+ 5 - 2
tests/CMakeLists.txt

@@ -29,7 +29,8 @@ set(test_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
                         ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.c
                         ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.c
                         ${PROJECT_SOURCE_DIR}/plugins/ua_nodestore_default.c
-                        ${PROJECT_SOURCE_DIR}/tests/testing_clock.c)
+                        ${PROJECT_SOURCE_DIR}/tests/testing_clock.c
+                        ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.c)
 
 add_library(open62541-testplugins OBJECT ${test_plugin_sources})
 add_dependencies(open62541-testplugins open62541)
@@ -40,7 +41,9 @@ if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
 endif()
 
 # Unit Test Definition Macro
-set(VALGRIND_FLAGS --quiet --trace-children=yes --leak-check=full)
+# For now we need to disable the libc freeres. See https://github.com/open62541/open62541/pull/1003#issuecomment-315045143
+# This also requires to disable the phtread cache with no-nptl-pthread-stackcache
+set(VALGRIND_FLAGS --quiet --trace-children=yes --leak-check=full --run-libc-freeres=no --sim-hints=no-nptl-pthread-stackcache)
 macro(add_test_valgrind TEST_NAME)
     if(UA_ENABLE_VALGRIND_UNIT_TESTS)
         add_test(${TEST_NAME} valgrind --error-exitcode=1 --suppressions=${PROJECT_SOURCE_DIR}/tools/valgrind_suppressions.supp ${VALGRIND_FLAGS} ${ARGN})

+ 2 - 1
tests/fuzz/CMakeLists.txt

@@ -39,7 +39,8 @@ set(fuzzing_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
         ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.c
         ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.c
         ${PROJECT_SOURCE_DIR}/plugins/ua_nodestore_default.c
-        ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.c)
+        ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.c
+        ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.c)
 
 add_library(open62541-fuzzplugins OBJECT ${fuzzing_plugin_sources})
 add_dependencies(open62541-fuzzplugins open62541)