Skip to content

Commit

Permalink
feat(server): Implement a transaction structure for updating trust li…
Browse files Browse the repository at this point in the history
…st and server certificates
  • Loading branch information
NoelGraf committed Jun 20, 2024
1 parent 3d0da9a commit d21bdb1
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 0 deletions.
34 changes: 34 additions & 0 deletions include/open62541/plugin/certificategroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,40 @@ struct UA_CertificateGroup {
void (*clear)(UA_CertificateGroup *certGroup);
};

struct UA_GDSCertificateInfo;
typedef struct UA_GDSCertificateInfo UA_GDSCertificateInfo;

struct UA_GDSCertificateInfo {
UA_ByteString certificate;
UA_ByteString privateKey;
UA_NodeId certificateGroup;
UA_NodeId certificateType;
};

struct UA_GDSTransaction;
typedef struct UA_GDSTransaction UA_GDSTransaction;

struct UA_GDSTransaction {
UA_NodeId sessionId;

size_t certGroupSize;
UA_CertificateGroup *certGroups;

size_t certificateInfosSize;
UA_GDSCertificateInfo *certificateInfos;
};

UA_GDSTransaction*
UA_GDSTransaction_new(const UA_NodeId sessionId);

/* Returns the appropriate CertificateGroup from the transaction.
* If the CertificateGroup does not exist in the transaction, it will be created. */
UA_CertificateGroup*
UA_GDSTransaction_getCertificateGroup(UA_GDSTransaction *transaction, const UA_CertificateGroup *certGroup);

void
UA_GDSTransaction_clear(UA_GDSTransaction *transaction);

/* Verify that the certificate has the applicationURI in the subject name. */
UA_EXPORT UA_StatusCode
UA_CertificateUtils_verifyApplicationURI(UA_RuleHandling ruleHandling,
Expand Down
68 changes: 68 additions & 0 deletions plugins/crypto/ua_certificategroup_none.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,74 @@ void UA_CertificateGroup_AcceptAll(UA_CertificateGroup *certGroup) {
certGroup->removeFromTrustList = NULL;
}

UA_GDSTransaction*
UA_GDSTransaction_new(const UA_NodeId sessionId) {
UA_GDSTransaction *transaction = (UA_GDSTransaction *) UA_calloc(1, sizeof(UA_GDSTransaction));
if(!transaction)
return NULL;

UA_NodeId_copy(&sessionId, &transaction->sessionId);

return transaction;
}

UA_CertificateGroup*
UA_GDSTransaction_getCertificateGroup(UA_GDSTransaction *transaction, const UA_CertificateGroup *certGroup) {
if(!transaction || !certGroup)
return NULL;

for(size_t i = 0; i < transaction->certGroupSize; i++) {
UA_CertificateGroup *group = &transaction->certGroups[i];
if(UA_NodeId_equal(&group->certificateGroupId, &certGroup->certificateGroupId))
return group;
}

/* If the certGroup does not exist, create a new one */
transaction->certGroups = (UA_CertificateGroup*)UA_realloc(transaction->certGroups, (transaction->certGroupSize + 1) * sizeof(UA_CertificateGroup));
if(!transaction->certGroups)
return NULL;

transaction->certGroupSize++;

UA_TrustListDataType trustList;
UA_TrustListDataType_init(&trustList);
trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;
certGroup->getTrustList((UA_CertificateGroup*)(uintptr_t)certGroup, &trustList);

UA_CertificateGroup_Memorystore(&transaction->certGroups[transaction->certGroupSize-1],
(UA_NodeId*)(uintptr_t)&certGroup->certificateGroupId, &trustList, certGroup->logging, NULL);

UA_TrustListDataType_clear(&trustList);

return &transaction->certGroups[transaction->certGroupSize-1];
}

void UA_GDSTransaction_clear(UA_GDSTransaction *transaction) {
if(!transaction)
return;

if(transaction->certGroups) {
for(size_t i = 0; i < transaction->certGroupSize; i++) {
transaction->certGroups[i].clear(&transaction->certGroups[i]);
}
UA_free(transaction->certGroups);
transaction->certGroupSize = 0;
transaction->certGroups = NULL;
}

if(transaction->certificateInfos) {
for(size_t i = 0; i < transaction->certificateInfosSize; i++) {
UA_ByteString_clear(&transaction->certificateInfos[i].certificate);
UA_ByteString_clear(&transaction->certificateInfos[i].privateKey);
UA_NodeId_clear(&transaction->certificateInfos[i].certificateGroup);
UA_NodeId_clear(&transaction->certificateInfos[i].certificateType);
}
UA_free(transaction->certificateInfos);
transaction->certificateInfosSize = 0;
transaction->certificateInfos = NULL;
}
}

#ifndef UA_ENABLE_ENCRYPTION
UA_StatusCode
UA_CertificateUtils_verifyApplicationURI(UA_RuleHandling ruleHandling,
Expand Down
83 changes: 83 additions & 0 deletions src/server/ua_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* Copyright 2019 (c) Kalycito Infotech Private Limited
* Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
* Copyright 2022 (c) Fraunhofer IOSB (Author: Andreas Ebner)
* Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
*/

#include "ua_server_internal.h"
Expand Down Expand Up @@ -544,6 +545,88 @@ notifySecureChannelsStopped(UA_Server *server, struct UA_ServerComponent *sc,
}
}

UA_StatusCode UA_EXPORT
UA_Server_applyChanges(UA_Server *server) {
UA_StatusCode retval = UA_STATUSCODE_GOOD;
if(!server->transaction)
return UA_STATUSCODE_BADNOTHINGTODO;

UA_GDSTransaction *transaction = server->transaction;

/* Apply Trust list changes */
for(size_t i = 0; i < transaction->certGroupSize; i++) {
UA_CertificateGroup transactionCertGroup = transaction->certGroups[i];
UA_TrustListDataType trustList;
UA_TrustListDataType_init(&trustList);
trustList.specifiedLists = UA_TRUSTLISTMASKS_ALL;
transactionCertGroup.getTrustList(&transactionCertGroup, &trustList);

UA_NodeId defaultApplicationGroup =
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP_TRUSTLIST);
UA_NodeId defaultUserTokenGroup =
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP_TRUSTLIST);
if(UA_NodeId_equal(&transactionCertGroup.certificateGroupId, &defaultApplicationGroup)) {
retval =
server->config.secureChannelPKI.setTrustList(&server->config.secureChannelPKI, &trustList);
}
if(UA_NodeId_equal(&transactionCertGroup.certificateGroupId, &defaultUserTokenGroup)) {
retval =
server->config.sessionPKI.setTrustList(&server->config.sessionPKI, &trustList);
}
UA_TrustListDataType_clear(&trustList);
if(retval != UA_STATUSCODE_GOOD)
goto cleanup;
}

/* Apply Server certificate changes */
for(size_t i = 0; i < transaction->certificateInfosSize; i++) {
UA_GDSCertificateInfo certInfo = transaction->certificateInfos[i];
UA_NodeId certGroupId = certInfo.certificateGroup;
UA_NodeId certTypeId = certInfo.certificateType;

for(size_t j = 0; j < server->config.securityPoliciesSize; j++) {
UA_SecurityPolicy *sp = &server->config.securityPolicies[j];
if(!sp) {
retval = UA_STATUSCODE_BADINTERNALERROR;
goto cleanup;
}

if(!UA_NodeId_equal(&certGroupId, &sp->certificateGroupId) ||
!UA_NodeId_equal(&certTypeId, &sp->certificateTypeId))
continue;

retval = sp->updateCertificateAndPrivateKey(sp, certInfo.certificate,
certInfo.privateKey);
if(retval != UA_STATUSCODE_GOOD)
goto cleanup;
}
for(size_t j = 0; j < server->config.endpointsSize; j++) {
UA_EndpointDescription *ed = &server->config.endpoints[j];
UA_SecurityPolicy *sp =
getSecurityPolicyByUri(server, &server->config.endpoints[j].securityPolicyUri);
if(!sp) {
retval = UA_STATUSCODE_BADINTERNALERROR;
goto cleanup;
}

if(!UA_NodeId_equal(&certGroupId, &sp->certificateGroupId) ||
!UA_NodeId_equal(&certTypeId, &sp->certificateTypeId))
continue;

UA_String_clear(&ed->serverCertificate);
retval = UA_String_copy(&sp->localCertificate, &ed->serverCertificate);
if(retval != UA_STATUSCODE_GOOD)
goto cleanup;
}
}

cleanup:
UA_GDSTransaction_clear(transaction);
transaction = NULL;

return retval;
}

UA_StatusCode
UA_Server_updateCertificate(UA_Server *server,
const UA_ByteString *oldCertificate,
Expand Down
3 changes: 3 additions & 0 deletions src/server/ua_server_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ struct UA_Server {
/* Statistics */
UA_SecureChannelStatistics secureChannelStatistics;
UA_ServerDiagnosticsSummaryDataType serverDiagnosticsSummary;

/* Transaction for certificate management */
UA_GDSTransaction *transaction;
};

/***********************/
Expand Down

0 comments on commit d21bdb1

Please sign in to comment.