Browse Source

UpdateSecurityPolicyCertificate

Markus Kocybik 5 years ago
parent
commit
9bdb86835b

+ 6 - 0
include/ua_plugin_securitypolicy.h

@@ -356,6 +356,12 @@ struct UA_SecurityPolicy {
 
     UA_Logger logger;
 
+    /*Updates the ApplicationInstanceCertificate and the corresponding
+    * private key at runtime. */
+    UA_StatusCode (*updateCertificateAndPrivateKey)(UA_SecurityPolicy *policy,
+                                                    const UA_ByteString newCertificate,
+                                                    const UA_ByteString newPrivateKey);
+
     /* Deletes the dynamic content of the policy */
     void (*deleteMembers)(UA_SecurityPolicy *policy);
 };

+ 8 - 0
include/ua_server.h

@@ -1249,6 +1249,14 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
 
 #endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */
 
+UA_StatusCode UA_EXPORT
+UA_Server_updateCertificate(UA_Server *server,
+                            const UA_ByteString *oldCertificate,
+                            const UA_ByteString *newCertificate,
+                            const UA_ByteString *newPrivateKey,
+                            UA_Boolean closeSessions,
+                            UA_Boolean closeSecureChannels);
+
 /**
  * Utility Functions
  * ----------------- */

+ 48 - 0
plugins/ua_securitypolicy_basic128rsa15.c

@@ -756,6 +756,53 @@ deleteMembers_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) {
     securityPolicy->policyContext = NULL;
 }
 
+static UA_StatusCode
+updateCertificateAndPrivateKey_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
+                                                const UA_ByteString newCertificate,
+                                                const UA_ByteString newPrivateKey) {
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(securityPolicy->policyContext == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&securityPolicy->localCertificate, newCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length);
+    securityPolicy->localCertificate.data[newCertificate.length] = '\0';
+    securityPolicy->localCertificate.length--;
+
+    /* Set the new private key */
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey,
+                                       newPrivateKey.data, newPrivateKey.length,
+                                       NULL, 0);
+    UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    retval = asym_makeThumbprint_sp_basic128rsa15(pc->securityPolicy,
+                                                  &securityPolicy->localCertificate,
+                                                  &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return retval;
+
+    error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not update certificate and private key");
+    if(securityPolicy->policyContext != NULL)
+        deleteMembers_sp_basic128rsa15(securityPolicy);
+    return retval;
+}
+
 static UA_StatusCode
 policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString localPrivateKey) {
@@ -961,6 +1008,7 @@ UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, UA_CertificateVerific
     channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
         channelContext_compareCertificate_sp_basic128rsa15;
 
+    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic128rsa15;
     policy->deleteMembers = deleteMembers_sp_basic128rsa15;
 
     return policyContext_newContext_sp_basic128rsa15(policy, localPrivateKey);

+ 50 - 0
plugins/ua_securitypolicy_basic256sha256.c

@@ -779,6 +779,55 @@ deleteMembers_sp_basic256sha256(UA_SecurityPolicy *securityPolicy) {
     securityPolicy->policyContext = NULL;
 }
 
+static UA_StatusCode
+updateCertificateAndPrivateKey_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
+                                                 const UA_ByteString newCertificate,
+                                                 const UA_ByteString newPrivateKey) {
+    if(securityPolicy == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    if(securityPolicy->policyContext == NULL)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    Basic256Sha256_PolicyContext *pc =
+            (Basic256Sha256_PolicyContext *) securityPolicy->policyContext;
+
+    UA_ByteString_deleteMembers(&securityPolicy->localCertificate);
+
+    UA_StatusCode retval =
+            UA_ByteString_allocBuffer(&securityPolicy->localCertificate, newCertificate.length + 1);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length);
+    securityPolicy->localCertificate.data[newCertificate.length] = '\0';
+    securityPolicy->localCertificate.length--;
+
+    /* Set the new private key */
+    mbedtls_pk_free(&pc->localPrivateKey);
+    mbedtls_pk_init(&pc->localPrivateKey);
+    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey,
+                                       newPrivateKey.data, newPrivateKey.length,
+                                       NULL, 0);
+    UA_MBEDTLS_ERRORHANDLING(UA_STATUSCODE_BADSECURITYCHECKSFAILED);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    retval = asym_makeThumbprint_sp_basic256sha256(pc->securityPolicy,
+                                                   &securityPolicy->localCertificate,
+                                                   &pc->localCertThumbprint);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto error;
+
+    return retval;
+
+    error:
+    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
+                 "Could not update certificate and private key");
+    if(securityPolicy->policyContext != NULL)
+        deleteMembers_sp_basic256sha256(securityPolicy);
+    return retval;
+}
+
 static UA_StatusCode
 policyContext_newContext_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                            const UA_ByteString localPrivateKey) {
@@ -984,6 +1033,7 @@ UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, UA_CertificateVerifi
     channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
         channelContext_compareCertificate_sp_basic256sha256;
 
+    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic256sha256;
     policy->deleteMembers = deleteMembers_sp_basic256sha256;
 
     return policyContext_newContext_sp_basic256sha256(policy, localPrivateKey);

+ 11 - 0
plugins/ua_securitypolicy_none.c

@@ -110,6 +110,16 @@ compareCertificate_none(const void *channelContext,
     return UA_STATUSCODE_GOOD;
 }
 
+static UA_StatusCode
+updateCertificateAndPrivateKey_none(UA_SecurityPolicy *policy,
+                                    const UA_ByteString newCertificate,
+                                    const UA_ByteString newPrivateKey) {
+    UA_ByteString_deleteMembers(&policy->localCertificate);
+    UA_ByteString_copy(&newCertificate, &policy->localCertificate);
+    return UA_STATUSCODE_GOOD;
+}
+
+
 static void
 policy_deletemembers_none(UA_SecurityPolicy *policy) {
     UA_ByteString_deleteMembers(&policy->localCertificate);
@@ -168,6 +178,7 @@ UA_SecurityPolicy_None(UA_SecurityPolicy *policy, UA_CertificateVerification *ce
     policy->channelModule.setRemoteSymSigningKey = setContextValue_none;
     policy->channelModule.setRemoteSymIv = setContextValue_none;
     policy->channelModule.compareCertificate = compareCertificate_none;
+    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_none;
     policy->deleteMembers = policy_deletemembers_none;
 
     return UA_STATUSCODE_GOOD;

+ 51 - 0
src/server/ua_server.c

@@ -372,3 +372,54 @@ UA_StatusCode
 UA_Server_removeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId) {
     return UA_Timer_removeRepeatedCallback(&server->timer, callbackId);
 }
+
+
+UA_StatusCode UA_EXPORT
+UA_Server_updateCertificate(UA_Server *server,
+                            const UA_ByteString *oldCertificate,
+                            const UA_ByteString *newCertificate,
+                            const UA_ByteString *newPrivateKey,
+                            UA_Boolean closeSessions,
+                            UA_Boolean closeSecureChannels) {
+
+    if (server == NULL || oldCertificate == NULL
+        || newCertificate == NULL || newPrivateKey == NULL) {
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    if (closeSessions) {
+        UA_SessionManager *sm = &server->sessionManager;
+        session_list_entry *current;
+        LIST_FOREACH(current, &sm->sessions, pointers) {
+            if (UA_ByteString_equal(oldCertificate,
+                                    &current->session.header.channel->securityPolicy->localCertificate)) {
+                UA_SessionManager_removeSession(sm, &current->session.header.authenticationToken);
+            }
+        }
+
+    }
+
+    if (closeSecureChannels) {
+        UA_SecureChannelManager *cm = &server->secureChannelManager;
+        channel_entry *entry;
+        TAILQ_FOREACH(entry, &cm->channels, pointers) {
+            if(UA_ByteString_equal(&entry->channel.securityPolicy->localCertificate, oldCertificate)){
+                UA_SecureChannelManager_close(cm, entry->channel.securityToken.channelId);
+            }
+        }
+    }
+
+    size_t index = 0;
+    while (index < server->config.endpointsSize) {
+        UA_EndpointDescription *ed = &server->config.endpoints[index].endpointDescription;
+        if (UA_ByteString_equal(&ed->serverCertificate, oldCertificate)) {
+            UA_String_deleteMembers(&ed->serverCertificate);
+            UA_String_copy(newCertificate, &ed->serverCertificate);
+            UA_SecurityPolicy *sp = &server->config.endpoints[index].securityPolicy;
+            sp->updateCertificateAndPrivateKey(sp, *newCertificate, *newPrivateKey);
+        }
+        index++;
+    }
+
+    return UA_STATUSCODE_GOOD;
+}