mirror of
https://github.com/open62541/open62541.git
synced 2026-10-17 04:42:09 +08:00
fix(plugin): generate valid filestore names for certificates and CRLs
Use the common name when available and fall back to the subject for CRLs and certificates without a common name. Check path formatting, propagate storage errors, and clean up trust-list data on every exit path.
This commit is contained in:
@@ -129,48 +129,43 @@ getCertFileName(const char *path, const char *fileExt,
|
||||
const UA_ByteString *certificate, char *fileNameBuf,
|
||||
size_t fileNameLen) {
|
||||
/* Check parameter */
|
||||
if(path == NULL || fileExt == NULL || certificate == NULL || fileNameBuf == NULL)
|
||||
if(path == NULL || fileExt == NULL || certificate == NULL ||
|
||||
fileNameBuf == NULL || fileNameLen == 0)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
||||
UA_Byte thumbprintData[40];
|
||||
UA_String thumbprint = {sizeof(thumbprintData), thumbprintData};
|
||||
UA_StatusCode retval = UA_CertificateUtils_getThumbprint(
|
||||
(UA_ByteString*)(uintptr_t)certificate, &thumbprint);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
|
||||
UA_String thumbprint = UA_STRING_NULL;
|
||||
thumbprint.length = 40;
|
||||
thumbprint.data = (UA_Byte*)UA_calloc(thumbprint.length, sizeof(UA_Byte));
|
||||
|
||||
UA_String commonName = UA_STRING_NULL;
|
||||
|
||||
UA_CertificateUtils_getThumbprint((UA_ByteString*)(uintptr_t)certificate, &thumbprint);
|
||||
UA_CertificateUtils_getCertCommonName((UA_ByteString*)(uintptr_t)certificate, &commonName);
|
||||
|
||||
if((thumbprint.length + commonName.length + 2) > fileNameLen) {
|
||||
UA_String_clear(&thumbprint);
|
||||
UA_String_clear(&commonName);
|
||||
UA_String name = UA_STRING_NULL;
|
||||
retval = UA_CertificateUtils_getCertCommonName(certificate, &name);
|
||||
if(retval != UA_STATUSCODE_GOOD) {
|
||||
retval = UA_CertificateUtils_getSubjectName(
|
||||
(UA_ByteString*)(uintptr_t)certificate, &name);
|
||||
}
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
if(name.length > UA_INT32_MAX) {
|
||||
UA_String_clear(&name);
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
}
|
||||
|
||||
char *thumbprintBuffer = (char*)UA_malloc(thumbprint.length + 1);
|
||||
char *commonNameBuffer = (char*)UA_malloc(commonName.length + 1);
|
||||
|
||||
memcpy(thumbprintBuffer, thumbprint.data, thumbprint.length);
|
||||
thumbprintBuffer[thumbprint.length] = '\0';
|
||||
memcpy(commonNameBuffer, commonName.data, commonName.length);
|
||||
commonNameBuffer[commonName.length] = '\0';
|
||||
|
||||
for(char *c = commonNameBuffer; *c; c++) {
|
||||
if(*c == '/' || *c == '\\')
|
||||
*c = '_';
|
||||
for(size_t i = 0; i < name.length; i++) {
|
||||
if(name.data[i] == '/' || name.data[i] == '\\' || name.data[i] < 0x20)
|
||||
name.data[i] = '_';
|
||||
}
|
||||
|
||||
if(mp_snprintf(fileNameBuf, fileNameLen, "%s/%s[%s]%s", path,
|
||||
commonNameBuffer,
|
||||
thumbprintBuffer, fileExt) < 0)
|
||||
int len = mp_snprintf(fileNameBuf, fileNameLen, "%s/%.*s[%.*s]%s", path,
|
||||
(int)name.length, (char*)name.data,
|
||||
(int)thumbprint.length,
|
||||
(char*)thumbprint.data, fileExt);
|
||||
if(len < 0 || (size_t)len >= fileNameLen)
|
||||
retval = UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
UA_String_clear(&thumbprint);
|
||||
UA_String_clear(&commonName);
|
||||
UA_free(thumbprintBuffer);
|
||||
UA_free(commonNameBuffer);
|
||||
UA_String_clear(&name);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -340,7 +335,7 @@ writeCertificates(const UA_ByteString *list, size_t listSize,
|
||||
char filename[UA_PATH_MAX] = {0};
|
||||
retval = getCertFileName(listPath, fileExt, &list[i], filename, UA_PATH_MAX);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
return retval;
|
||||
|
||||
/* Store data in file */
|
||||
retval = writeByteStringToFile(filename, &list[i]);
|
||||
@@ -361,7 +356,10 @@ writeTrustList(const UA_ByteString *list, size_t listSize,
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
|
||||
char listPath[UA_PATH_MAX] = {0};
|
||||
mp_snprintf(listPath, UA_PATH_MAX, "%.*s", (int)path.length, (char *)path.data);
|
||||
int len = mp_snprintf(listPath, UA_PATH_MAX, "%.*s",
|
||||
(int)path.length, (char*)path.data);
|
||||
if(len < 0 || len >= UA_PATH_MAX)
|
||||
return UA_STATUSCODE_BADINTERNALERROR;
|
||||
/* remove existing files in directory */
|
||||
UA_StatusCode retval = removeAllFilesFromDir(listPath, false);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
@@ -382,37 +380,41 @@ writeTrustStore(UA_CertificateGroup *certGroup, const UA_UInt32 trustListMask) {
|
||||
UA_TrustListDataType_init(&trustList);
|
||||
trustList.specifiedLists = trustListMask;
|
||||
|
||||
context->store->getTrustList(context->store, &trustList);
|
||||
UA_StatusCode retval =
|
||||
context->store->getTrustList(context->store, &trustList);
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
goto cleanup;
|
||||
|
||||
UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
||||
if(trustList.specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES) {
|
||||
retval = writeTrustList(trustList.trustedCertificates,
|
||||
trustList.trustedCertificatesSize, context->trustedCertFolder,
|
||||
".der");
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
goto cleanup;
|
||||
}
|
||||
if(trustList.specifiedLists & UA_TRUSTLISTMASKS_TRUSTEDCRLS) {
|
||||
retval = writeTrustList(trustList.trustedCrls,
|
||||
trustList.trustedCrlsSize, context->trustedCrlFolder,
|
||||
".crl");
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
goto cleanup;
|
||||
}
|
||||
if(trustList.specifiedLists & UA_TRUSTLISTMASKS_ISSUERCERTIFICATES) {
|
||||
retval = writeTrustList(trustList.issuerCertificates,
|
||||
trustList.issuerCertificatesSize, context->issuerCertFolder,
|
||||
".der");
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
goto cleanup;
|
||||
}
|
||||
if(trustList.specifiedLists & UA_TRUSTLISTMASKS_ISSUERCRLS) {
|
||||
retval = writeTrustList(trustList.issuerCrls,
|
||||
trustList.issuerCrlsSize, context->issuerCrlFolder,
|
||||
".crl");
|
||||
if(retval != UA_STATUSCODE_GOOD)
|
||||
return retval;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
UA_TrustListDataType_clear(&trustList);
|
||||
|
||||
return retval;
|
||||
|
||||
@@ -92,7 +92,7 @@ UA_CertificateGroup_Filestore(UA_CertificateGroup *certGroup,
|
||||
const UA_String storePath,
|
||||
const UA_Logger *logger,
|
||||
const UA_KeyValueMap *params);
|
||||
#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */
|
||||
#endif /* supported filestore platforms */
|
||||
|
||||
#endif /* UA_ENABLE_ENCRYPTION */
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <open62541/client.h>
|
||||
#include <open62541/client_config_default.h>
|
||||
#include <open62541/plugin/certificategroup_default.h>
|
||||
#include <open62541/plugin/log_stdout.h>
|
||||
#include <open62541/server.h>
|
||||
#include <open62541/server_config_default.h>
|
||||
|
||||
@@ -19,13 +20,18 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "test_helpers.h"
|
||||
#include "../common.h"
|
||||
#include "certificates.h"
|
||||
#include "certificate_eku.h"
|
||||
#include "check.h"
|
||||
#include "thread_wrapper.h"
|
||||
|
||||
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
|
||||
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || \
|
||||
defined(__APPLE__) || defined(__OpenBSD__)
|
||||
#include "mp_printf.h"
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32)
|
||||
#define TEST_PATH_MAX 256
|
||||
#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */
|
||||
|
||||
@@ -588,6 +594,63 @@ START_TEST(verify_expired_certificate_status_depends_on_trust) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || \
|
||||
defined(__APPLE__) || defined(__OpenBSD__)
|
||||
START_TEST(filestore_uses_crl_issuer_in_filename) {
|
||||
UA_CertificateGroup group;
|
||||
memset(&group, 0, sizeof(group));
|
||||
UA_NodeId groupId = UA_NS0ID(
|
||||
SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP);
|
||||
UA_String storePath = UA_STRING("pki-crl-filename-test");
|
||||
UA_StatusCode retval = UA_CertificateGroup_Filestore(
|
||||
&group, &groupId, storePath, UA_Log_Stdout, NULL);
|
||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
UA_ByteString caCertificate = {ROOT_CERT_DER_LENGTH, ROOT_CERT_DER_DATA};
|
||||
UA_ByteString crl = {ROOT_EMPTY_CRL_PEM_LENGTH, ROOT_EMPTY_CRL_PEM_DATA};
|
||||
UA_TrustListDataType trustList;
|
||||
UA_TrustListDataType_init(&trustList);
|
||||
trustList.specifiedLists = UA_TRUSTLISTMASKS_TRUSTEDCERTIFICATES |
|
||||
UA_TRUSTLISTMASKS_TRUSTEDCRLS;
|
||||
trustList.trustedCertificates = &caCertificate;
|
||||
trustList.trustedCertificatesSize = 1;
|
||||
trustList.trustedCrls = &crl;
|
||||
trustList.trustedCrlsSize = 1;
|
||||
retval = group.setTrustList(&group, &trustList);
|
||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
UA_String issuer = UA_STRING_NULL;
|
||||
retval = UA_CertificateUtils_getSubjectName(&crl, &issuer);
|
||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||
for(size_t i = 0; i < issuer.length; i++) {
|
||||
if(issuer.data[i] == '/' || issuer.data[i] == '\\' || issuer.data[i] < 0x20)
|
||||
issuer.data[i] = '_';
|
||||
}
|
||||
|
||||
UA_Byte thumbprintData[40];
|
||||
UA_String thumbprint = {sizeof(thumbprintData), thumbprintData};
|
||||
retval = UA_CertificateUtils_getThumbprint(&crl, &thumbprint);
|
||||
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
||||
|
||||
char filename[2048];
|
||||
int len = mp_snprintf(
|
||||
filename, sizeof(filename),
|
||||
"pki-crl-filename-test/ApplCerts/trusted/crl/%.*s[%.*s].crl",
|
||||
(int)issuer.length, (char*)issuer.data,
|
||||
(int)thumbprint.length, (char*)thumbprint.data);
|
||||
ck_assert_int_ge(len, 0);
|
||||
ck_assert_uint_lt((size_t)len, sizeof(filename));
|
||||
|
||||
UA_ByteString storedCrl = loadFile(filename);
|
||||
ck_assert(UA_ByteString_equal(&storedCrl, &crl));
|
||||
|
||||
UA_ByteString_clear(&storedCrl);
|
||||
UA_String_clear(&issuer);
|
||||
group.clear(&group);
|
||||
}
|
||||
END_TEST
|
||||
#endif
|
||||
|
||||
#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS
|
||||
START_TEST(memorystore_rejects_invalid_initial_trust_material) {
|
||||
UA_Byte invalidData[] = {0x01, 0x02, 0x03};
|
||||
@@ -793,6 +856,13 @@ static Suite* testSuite_encryption(void) {
|
||||
suite_add_tcase(s,tc_encryption_filestore);
|
||||
#endif /* UA_ENABLE_ENCRYPTION */
|
||||
#endif /* defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) */
|
||||
|
||||
#if defined(__linux__) || defined(UA_ARCHITECTURE_WIN32) || \
|
||||
defined(__APPLE__) || defined(__OpenBSD__)
|
||||
TCase *tc_filestore_filename = tcase_create("CertificateGroup filenames");
|
||||
tcase_add_test(tc_filestore_filename, filestore_uses_crl_issuer_in_filename);
|
||||
suite_add_tcase(s, tc_filestore_filename);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user