mirror of
https://github.com/open62541/open62541.git
synced 2026-10-17 04:42:09 +08:00
6901aedc07
Port keyless certificate validation into the GDS receiver driver instead of restoring the removed server implementation. Preserve master's timer batching, PubSub lifecycle and client HTTP configuration handling. Adapt Publish cancellation to response tokens and the HEL/fuzz harnesses to the explicit TCP driver. Keep SKS policy history and custom datatype ownership intact, including failed replacement configuration cleanup. Retain TPM error cleanup while enforcing key-handle and nonce lengths. Validation: - Full mbedTLS unit-test build with full namespace, GDS, SKS and Query. - 21 affected suites passed with ASan/UBSan, plus 9 isolated SKS ownership and lifecycle checks. - OpenSSL certificate update, GDS information model and client encryption suites passed with sanitizers. - OPN, MSG and binary-message fuzzers each completed 100 sanitizer runs. - Both TPM PubSub policy sources passed compilation checks. The full SKS client suite timed out after multicast UDP sends reported "No route to host" on this machine; its affected ownership and lifecycle cases passed separately. No live TPM hardware validation was performed.
388 lines
17 KiB
C
388 lines
17 KiB
C
/* 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/.
|
|
*
|
|
* Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
|
|
*/
|
|
|
|
#include <open62541/server_config_default.h>
|
|
#include <open62541/plugin/log_stdout.h>
|
|
#include <open62541/plugin/create_certificate.h>
|
|
#include <open62541/driver/gds_receiver.h>
|
|
|
|
#include "ua_server_internal.h"
|
|
|
|
#include <check.h>
|
|
#include "test_helpers.h"
|
|
#include "certificates.h"
|
|
|
|
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
|
|
#include "mp_printf.h"
|
|
#define TEST_PATH_MAX 256
|
|
#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */
|
|
|
|
UA_Server *server;
|
|
UA_GDSReceiver *receiver;
|
|
|
|
static void setup(void) {
|
|
/* Load certificate and private key */
|
|
UA_ByteString certificate;
|
|
certificate.length = CERT_DER_LENGTH;
|
|
certificate.data = CERT_DER_DATA;
|
|
|
|
UA_ByteString privateKey;
|
|
privateKey.length = KEY_DER_LENGTH;
|
|
privateKey.data = KEY_DER_DATA;
|
|
|
|
server = UA_Server_newForUnitTestWithSecurityPolicies(4840, &certificate, &privateKey,
|
|
NULL, 0, NULL, 0, NULL, 0);
|
|
ck_assert(server != NULL);
|
|
receiver = UA_GDSReceiver_new();
|
|
ck_assert_ptr_nonnull(receiver);
|
|
ck_assert_uint_eq(UA_Server_addDriver(server, &receiver->drv),
|
|
UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(UA_Server_run_startup(server), UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
|
|
static void setup2(void) {
|
|
/* Load certificate and private key */
|
|
UA_ByteString certificate;
|
|
certificate.length = CERT_DER_LENGTH;
|
|
certificate.data = CERT_DER_DATA;
|
|
|
|
UA_ByteString privateKey;
|
|
privateKey.length = KEY_DER_LENGTH;
|
|
privateKey.data = KEY_DER_DATA;
|
|
|
|
char storePathDir[TEST_PATH_MAX];
|
|
getcwd(storePathDir, TEST_PATH_MAX - 4);
|
|
mp_snprintf(storePathDir, TEST_PATH_MAX, "%s/pki", storePathDir);
|
|
|
|
const UA_String storePath = UA_STRING(storePathDir);
|
|
server =
|
|
UA_Server_newForUnitTestWithSecurityPolicies_Filestore(4840, &certificate,
|
|
&privateKey, storePath);
|
|
ck_assert(server != NULL);
|
|
receiver = UA_GDSReceiver_new();
|
|
ck_assert_ptr_nonnull(receiver);
|
|
ck_assert_uint_eq(UA_Server_addDriver(server, &receiver->drv),
|
|
UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(UA_Server_run_startup(server), UA_STATUSCODE_GOOD);
|
|
}
|
|
#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */
|
|
|
|
static void teardown(void) {
|
|
ck_assert_uint_eq(UA_Server_run_shutdown(server), UA_STATUSCODE_GOOD);
|
|
UA_Server_delete(server);
|
|
}
|
|
|
|
static void generateCertificate(UA_ByteString *certificate, UA_ByteString *privKey) {
|
|
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.unconfigured.application")
|
|
};
|
|
UA_UInt32 lenSubjectAltName = 2;
|
|
UA_KeyValueMap *kvm = UA_KeyValueMap_new();
|
|
UA_UInt16 expiresIn = 14;
|
|
UA_KeyValueMap_setScalar(kvm, UA_QUALIFIEDNAME(0, "expires-in-days"),
|
|
(void *)&expiresIn, &UA_TYPES[UA_TYPES_UINT16]);
|
|
UA_UInt16 keyLength = 2048;
|
|
UA_KeyValueMap_setScalar(kvm, UA_QUALIFIEDNAME(0, "key-size-bits"),
|
|
(void *)&keyLength, &UA_TYPES[UA_TYPES_UINT16]);
|
|
UA_CreateCertificate(UA_Log_Stdout, subject, lenSubject, subjectAltName,
|
|
lenSubjectAltName, UA_CERTIFICATEFORMAT_DER, kvm,
|
|
privKey, certificate);
|
|
|
|
UA_KeyValueMap_delete(kvm);
|
|
}
|
|
|
|
START_TEST(update_certificate) {
|
|
UA_ByteString newCertificate = UA_BYTESTRING_NULL;
|
|
UA_ByteString newPrivateKey = UA_BYTESTRING_NULL;
|
|
|
|
generateCertificate(&newCertificate, &newPrivateKey);
|
|
|
|
UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
|
UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
|
|
UA_StatusCode retval =
|
|
UA_GDSReceiver_updateCertificate(receiver, defaultApplicationGroup, certTypRsaSha256,
|
|
newCertificate, &newPrivateKey);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_ByteString_clear(&newCertificate);
|
|
UA_ByteString_clear(&newPrivateKey);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(update_certificate_wrongKey) {
|
|
UA_ByteString newCertificate = UA_BYTESTRING_NULL;
|
|
UA_ByteString newPrivateKey = UA_BYTESTRING_NULL;
|
|
|
|
generateCertificate(&newCertificate, &newPrivateKey);
|
|
|
|
UA_ByteString wrongPrivateKey;
|
|
wrongPrivateKey.length = KEY_DER_LENGTH;
|
|
wrongPrivateKey.data = KEY_DER_DATA;
|
|
|
|
UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
|
UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
|
|
UA_StatusCode retval =
|
|
UA_GDSReceiver_updateCertificate(receiver, defaultApplicationGroup, certTypRsaSha256,
|
|
newCertificate, &wrongPrivateKey);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADNOTSUPPORTED);
|
|
|
|
UA_ByteString_clear(&newCertificate);
|
|
UA_ByteString_clear(&newPrivateKey);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(update_certificate_noKey) {
|
|
UA_ByteString newCertificate;
|
|
newCertificate.length = CERT_DER_LENGTH;
|
|
newCertificate.data = CERT_DER_DATA;
|
|
|
|
UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
|
UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
|
|
UA_StatusCode retval =
|
|
UA_GDSReceiver_updateCertificate(receiver, defaultApplicationGroup, certTypRsaSha256,
|
|
newCertificate, NULL);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
END_TEST
|
|
|
|
/* Only the certificate types of the configured SecurityPolicies are
|
|
* advertised. No SecurityPolicy of the default configuration uses RsaMin. */
|
|
START_TEST(certificate_types_configured) {
|
|
UA_Variant value;
|
|
UA_Variant_init(&value);
|
|
UA_StatusCode retval = UA_Server_readValue(server,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_CERTIFICATETYPES),
|
|
&value);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert(UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_NODEID]));
|
|
ck_assert_uint_eq(value.arrayLength, 1);
|
|
UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
ck_assert(UA_NodeId_equal((UA_NodeId*)value.data, &certTypRsaSha256));
|
|
UA_Variant_clear(&value);
|
|
}
|
|
END_TEST
|
|
|
|
/* UpdateCertificate refuses a certificate type that is not advertised */
|
|
START_TEST(update_certificate_unconfiguredType) {
|
|
UA_ByteString certificate = {CERT_DER_LENGTH, CERT_DER_DATA};
|
|
UA_ByteString privateKey = {KEY_DER_LENGTH, KEY_DER_DATA};
|
|
UA_String privateKeyFormat = UA_STRING_STATIC("DER");
|
|
UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
|
UA_NodeId certTypRsaMin = UA_NODEID_NUMERIC(0, UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE);
|
|
|
|
UA_Variant input[6];
|
|
memset(input, 0, sizeof(input));
|
|
UA_Variant_setScalar(&input[0], &defaultApplicationGroup, &UA_TYPES[UA_TYPES_NODEID]);
|
|
UA_Variant_setScalar(&input[1], &certTypRsaMin, &UA_TYPES[UA_TYPES_NODEID]);
|
|
UA_Variant_setScalar(&input[2], &certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
|
|
UA_Variant_setArray(&input[3], NULL, 0, &UA_TYPES[UA_TYPES_BYTESTRING]);
|
|
UA_Variant_setScalar(&input[4], &privateKeyFormat, &UA_TYPES[UA_TYPES_STRING]);
|
|
UA_Variant_setScalar(&input[5], &privateKey, &UA_TYPES[UA_TYPES_BYTESTRING]);
|
|
|
|
UA_CallMethodRequest request;
|
|
UA_CallMethodRequest_init(&request);
|
|
request.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION);
|
|
request.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_UPDATECERTIFICATE);
|
|
request.inputArgumentsSize = 6;
|
|
request.inputArguments = input;
|
|
|
|
UA_CallMethodResult result = UA_Server_call(server, &request);
|
|
ck_assert_uint_eq(result.statusCode, UA_STATUSCODE_BADINVALIDARGUMENT);
|
|
UA_CallMethodResult_clear(&result);
|
|
}
|
|
END_TEST
|
|
|
|
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
|
|
/* The filestore configuration also has the Basic128Rsa15 and Basic256
|
|
* SecurityPolicies. So RsaMin is advertised as well. */
|
|
START_TEST(certificate_types_configured_filestore) {
|
|
UA_Variant value;
|
|
UA_Variant_init(&value);
|
|
UA_StatusCode retval = UA_Server_readValue(server,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_CERTIFICATETYPES),
|
|
&value);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert(UA_Variant_hasArrayType(&value, &UA_TYPES[UA_TYPES_NODEID]));
|
|
ck_assert_uint_eq(value.arrayLength, 2);
|
|
UA_NodeId certTypRsaMin = UA_NODEID_NUMERIC(0, UA_NS0ID_RSAMINAPPLICATIONCERTIFICATETYPE);
|
|
UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
ck_assert(UA_NodeId_equal(&((UA_NodeId*)value.data)[0], &certTypRsaMin));
|
|
ck_assert(UA_NodeId_equal(&((UA_NodeId*)value.data)[1], &certTypRsaSha256));
|
|
UA_Variant_clear(&value);
|
|
}
|
|
END_TEST
|
|
#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */
|
|
|
|
START_TEST(addDriver_rejectsDuplicateGDSReceiver) {
|
|
UA_GDSReceiver *duplicate = UA_GDSReceiver_new();
|
|
ck_assert_ptr_nonnull(duplicate);
|
|
|
|
ck_assert_uint_eq(UA_Server_addDriver(server, &duplicate->drv),
|
|
UA_STATUSCODE_BADALREADYEXISTS);
|
|
ck_assert_ptr_null(duplicate->drv.server);
|
|
ck_assert_uint_eq(duplicate->drv.free(&duplicate->drv),
|
|
UA_STATUSCODE_GOOD);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(update_certificate_preflightsAllEndpoints) {
|
|
UA_ServerConfig *config = UA_Server_getConfig(server);
|
|
UA_NodeId certificateType =
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
UA_SecurityPolicy *policy = NULL;
|
|
for(size_t i = 0; i < config->securityPoliciesSize; i++) {
|
|
if(UA_NodeId_equal(&config->securityPolicies[i].certificateTypeId,
|
|
&certificateType)) {
|
|
policy = &config->securityPolicies[i];
|
|
break;
|
|
}
|
|
}
|
|
ck_assert_ptr_nonnull(policy);
|
|
|
|
UA_ByteString oldCertificate = UA_BYTESTRING_NULL;
|
|
ck_assert_uint_eq(UA_ByteString_copy(&policy->localCertificate,
|
|
&oldCertificate),
|
|
UA_STATUSCODE_GOOD);
|
|
|
|
size_t oldSize = config->endpointsSize;
|
|
UA_EndpointDescription *endpoints = (UA_EndpointDescription*)
|
|
UA_realloc(config->endpoints,
|
|
sizeof(UA_EndpointDescription) * (oldSize + 1));
|
|
ck_assert_ptr_nonnull(endpoints);
|
|
config->endpoints = endpoints;
|
|
UA_EndpointDescription_init(&config->endpoints[oldSize]);
|
|
config->endpoints[oldSize].securityPolicyUri =
|
|
UA_STRING_ALLOC("urn:invalid-security-policy");
|
|
config->endpointsSize++;
|
|
|
|
UA_ByteString newCertificate = UA_BYTESTRING_NULL;
|
|
UA_ByteString newPrivateKey = UA_BYTESTRING_NULL;
|
|
generateCertificate(&newCertificate, &newPrivateKey);
|
|
|
|
UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(
|
|
0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
|
UA_StatusCode res = UA_GDSReceiver_updateCertificate(
|
|
receiver, defaultApplicationGroup, certificateType,
|
|
newCertificate, &newPrivateKey);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADINTERNALERROR);
|
|
ck_assert(UA_ByteString_equal(&policy->localCertificate, &oldCertificate));
|
|
|
|
UA_ByteString_clear(&newCertificate);
|
|
UA_ByteString_clear(&newPrivateKey);
|
|
UA_ByteString_clear(&oldCertificate);
|
|
}
|
|
END_TEST
|
|
|
|
/* The SecurityPolicy#None endpoint presents the certificate of the None
|
|
* SecurityPolicy (GetEndpoints). It gets the new certificate as well. */
|
|
START_TEST(update_certificate_noneEndpoint) {
|
|
UA_ServerConfig *config = UA_Server_getConfig(server);
|
|
UA_SecurityPolicy *nonePolicy = NULL;
|
|
for(size_t i = 0; i < config->securityPoliciesSize; i++) {
|
|
if(config->securityPolicies[i].policyType == UA_SECURITYPOLICYTYPE_NONE)
|
|
nonePolicy = &config->securityPolicies[i];
|
|
}
|
|
ck_assert_ptr_nonnull(nonePolicy);
|
|
UA_ByteString oldCertificate = UA_BYTESTRING_NULL;
|
|
ck_assert_uint_eq(UA_ByteString_copy(&nonePolicy->localCertificate,
|
|
&oldCertificate),
|
|
UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_gt(oldCertificate.length, 0);
|
|
|
|
UA_ByteString newCertificate = UA_BYTESTRING_NULL;
|
|
UA_ByteString newPrivateKey = UA_BYTESTRING_NULL;
|
|
generateCertificate(&newCertificate, &newPrivateKey);
|
|
|
|
UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(
|
|
0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
|
UA_NodeId certTypRsaSha256 =
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
ck_assert_uint_eq(UA_GDSReceiver_updateCertificate(
|
|
receiver, defaultApplicationGroup, certTypRsaSha256,
|
|
newCertificate, &newPrivateKey),
|
|
UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert(UA_ByteString_equal(&nonePolicy->localCertificate,
|
|
&newCertificate));
|
|
for(size_t i = 0; i < config->endpointsSize; i++)
|
|
ck_assert(!UA_ByteString_equal(&config->endpoints[i].serverCertificate,
|
|
&oldCertificate));
|
|
|
|
UA_ByteString_clear(&oldCertificate);
|
|
UA_ByteString_clear(&newCertificate);
|
|
UA_ByteString_clear(&newPrivateKey);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(update_certificate_noKey_invalid) {
|
|
UA_ByteString newCertificate = UA_BYTESTRING("not a certificate");
|
|
|
|
UA_NodeId defaultApplicationGroup = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
|
UA_NodeId certTypRsaSha256 = UA_NODEID_NUMERIC(0, UA_NS0ID_RSASHA256APPLICATIONCERTIFICATETYPE);
|
|
|
|
UA_StatusCode retval =
|
|
UA_GDSReceiver_updateCertificate(receiver, defaultApplicationGroup, certTypRsaSha256,
|
|
newCertificate, NULL);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADCERTIFICATEINVALID);
|
|
}
|
|
END_TEST
|
|
|
|
static Suite* testSuite_create_certificate(void) {
|
|
Suite *s = suite_create("Update Certificate");
|
|
TCase *tc_cert = tcase_create("Update Certificate");
|
|
tcase_add_checked_fixture(tc_cert, setup, teardown);
|
|
#ifdef UA_ENABLE_ENCRYPTION
|
|
tcase_add_test(tc_cert, update_certificate);
|
|
tcase_add_test(tc_cert, update_certificate_wrongKey);
|
|
tcase_add_test(tc_cert, update_certificate_noKey);
|
|
tcase_add_test(tc_cert, certificate_types_configured);
|
|
tcase_add_test(tc_cert, update_certificate_unconfiguredType);
|
|
tcase_add_test(tc_cert, addDriver_rejectsDuplicateGDSReceiver);
|
|
tcase_add_test(tc_cert, update_certificate_preflightsAllEndpoints);
|
|
tcase_add_test(tc_cert, update_certificate_noneEndpoint);
|
|
tcase_add_test(tc_cert, update_certificate_noKey_invalid);
|
|
#endif /* UA_ENABLE_ENCRYPTION */
|
|
suite_add_tcase(s,tc_cert);
|
|
|
|
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
|
|
TCase *tc_cert_filestore = tcase_create("Update Certificate Filestore");
|
|
tcase_add_checked_fixture(tc_cert_filestore, setup2, teardown);
|
|
#ifdef UA_ENABLE_ENCRYPTION
|
|
tcase_add_test(tc_cert_filestore, update_certificate);
|
|
tcase_add_test(tc_cert_filestore, update_certificate_wrongKey);
|
|
tcase_add_test(tc_cert_filestore, update_certificate_noKey);
|
|
tcase_add_test(tc_cert_filestore, certificate_types_configured_filestore);
|
|
tcase_add_test(tc_cert_filestore, addDriver_rejectsDuplicateGDSReceiver);
|
|
tcase_add_test(tc_cert_filestore, update_certificate_preflightsAllEndpoints);
|
|
tcase_add_test(tc_cert_filestore, update_certificate_noneEndpoint);
|
|
tcase_add_test(tc_cert_filestore, update_certificate_noKey_invalid);
|
|
#endif /* UA_ENABLE_ENCRYPTION */
|
|
suite_add_tcase(s,tc_cert_filestore);
|
|
#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */
|
|
|
|
return s;
|
|
}
|
|
|
|
int main(void) {
|
|
Suite *s = testSuite_create_certificate();
|
|
SRunner *sr = srunner_create(s);
|
|
srunner_set_fork_status(sr, CK_NOFORK);
|
|
srunner_run_all(sr,CK_NORMAL);
|
|
int number_failed = srunner_ntests_failed(sr);
|
|
srunner_free(sr);
|
|
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
}
|