Browse Source

Server: Reload folders with certificates during runtime

Julius Pfrommer 4 years ago
parent
commit
6f79ec6e8f
3 changed files with 257 additions and 8 deletions
  1. 66 8
      examples/server_ctt.c
  2. 8 0
      plugins/include/open62541/plugin/pki_default.h
  3. 183 0
      plugins/ua_pki_default.c

+ 66 - 8
examples/server_ctt.c

@@ -9,9 +9,10 @@
 #define _CRT_SECURE_NO_WARNINGS /* disable fopen deprication warning in msvs */
 #endif
 
-#include <open62541/plugin/log_stdout.h>
 #include <open62541/server.h>
+#include <open62541/plugin/log_stdout.h>
 #include <open62541/server_config_default.h>
+#include <open62541/plugin/pki_default.h>
 
 #include <signal.h>
 #include <stdlib.h>
@@ -936,9 +937,15 @@ usage(void) {
                    "server_ctt [<server-certificate.der>]\n"
 #else
                    "server_ctt <server-certificate.der> <private-key.der>\n"
+#ifndef __linux__
                    "\t[--trustlist <tl1.ctl> <tl2.ctl> ... ]\n"
                    "\t[--issuerlist <il1.der> <il2.der> ... ]\n"
                    "\t[--revocationlist <rv1.crl> <rv2.crl> ...]\n"
+#else
+                   "\t[--trustlistFolder <folder>]\n"
+                   "\t[--issuerlistFolder <folder>]\n"
+                   "\t[--revocationlistFolder <folder>]\n"
+#endif
                    "\t[--enableUnencrypted]\n"
                    "\t[--enableOutdatedSecurityPolicy]\n"
                    "\t[--enableTimestampCheck]\n"
@@ -990,12 +997,6 @@ int main(int argc, char **argv) {
         pos++;
     }
 
-    UA_ByteString trustList[100];
-    size_t trustListSize = 0;
-    UA_ByteString issuerList[100];
-    size_t issuerListSize = 0;
-    UA_ByteString revocationList[100];
-    size_t revocationListSize = 0;
     char filetype = ' '; /* t==trustlist, l == issuerList, r==revocationlist */
     UA_Boolean enableUnencr = false;
     UA_Boolean enableSec = false;
@@ -1004,6 +1005,19 @@ int main(int argc, char **argv) {
     UA_Boolean disableBasic256 = false;
     UA_Boolean disableBasic256Sha256 = false;
 
+#ifndef __linux__
+    UA_ByteString trustList[100];
+    size_t trustListSize = 0;
+    UA_ByteString issuerList[100];
+    size_t issuerListSize = 0;
+    UA_ByteString revocationList[100];
+    size_t revocationListSize = 0;
+#else
+    const char *trustlistFolder = NULL;
+    const char *issuerlistFolder = NULL;
+    const char *revocationlistFolder = NULL;
+#endif
+
 #endif
 
     UA_Boolean enableAnon = false;
@@ -1047,6 +1061,7 @@ int main(int argc, char **argv) {
             continue;
         }        
 
+#ifndef __linux__
         if(strcmp(argv[pos], "--trustlist") == 0) {
             filetype = 't';
             continue;
@@ -1109,6 +1124,38 @@ int main(int argc, char **argv) {
             revocationListSize++;
             continue;
         }
+#else
+        if(strcmp(argv[pos], "--trustlistFolder") == 0) {
+            filetype = 't';
+            continue;
+        }
+
+        if(strcmp(argv[pos], "--issuerlistFolder") == 0) {
+            filetype = 'l';
+            continue;
+        }
+
+        if(strcmp(argv[pos], "--revocationlistFolder") == 0) {
+            filetype = 'r';
+            continue;
+        }
+
+        if(filetype == 't') {
+            trustlistFolder = argv[pos];
+            continue;
+        }
+
+        if(filetype == 'l') {
+            issuerlistFolder = argv[pos];
+            continue;
+        }
+
+        if(filetype == 'r') {
+            revocationlistFolder = argv[pos];
+            continue;
+        }
+#endif
+
 #endif
 
         usage();
@@ -1116,11 +1163,22 @@ int main(int argc, char **argv) {
     }
 
 #ifdef UA_ENABLE_ENCRYPTION
+#ifndef __linux__
     UA_ServerConfig_setDefaultWithSecurityPolicies(&config, 4840,
                                                    &certificate, &privateKey,
                                                    trustList, trustListSize,
                                                    issuerList, issuerListSize,
                                                    revocationList, revocationListSize);
+#else
+    UA_ServerConfig_setDefaultWithSecurityPolicies(&config, 4840,
+                                                   &certificate, &privateKey,
+                                                   NULL, 0, NULL, 0, NULL, 0);
+    config.certificateVerification.deleteMembers(&config.certificateVerification);
+    UA_CertificateVerification_CertFolders(&config.certificateVerification,
+                                           trustlistFolder, issuerlistFolder,
+                                           revocationlistFolder);
+#endif
+
     if(!enableUnencr)
         disableUnencrypted(&config);
     if(!enableSec)
@@ -1158,7 +1216,7 @@ int main(int argc, char **argv) {
 
     /* Clean up temp values */
     UA_ByteString_clear(&certificate);
-#ifdef UA_ENABLE_ENCRYPTION
+#if defined(UA_ENABLE_ENCRYPTION) && !defined(__linux__)
     UA_ByteString_clear(&privateKey);
     for(size_t i = 0; i < trustListSize; i++)
         UA_ByteString_clear(&trustList[i]);

+ 8 - 0
plugins/include/open62541/plugin/pki_default.h

@@ -29,6 +29,14 @@ UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv,
                                      const UA_ByteString *certificateRevocationList,
                                      size_t certificateRevocationListSize);
 
+#if __linux__ /* Linux only so far */
+UA_EXPORT UA_StatusCode
+UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv,
+                                       const char *trustListFolder,
+                                       const char *issuerListFolder,
+                                       const char *revocationListFolder);
+#endif
+
 #endif
 
 _UA_END_DECLS

+ 183 - 0
plugins/ua_pki_default.c

@@ -3,13 +3,17 @@
  *
  *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
  *    Copyright 2019 (c) Kalycito Infotech Private Limited
+ *    Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB
  */
 
+#include <open62541/server_config.h>
 #include <open62541/plugin/pki_default.h>
+#include <open62541/plugin/log_stdout.h>
 
 #ifdef UA_ENABLE_ENCRYPTION
 #include <mbedtls/x509.h>
 #include <mbedtls/x509_crt.h>
+#include <mbedtls/error.h>
 #endif
 
 #define REMOTECERTIFICATETRUSTED 1
@@ -48,11 +52,143 @@ void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) {
 #ifdef UA_ENABLE_ENCRYPTION
 
 typedef struct {
+    /* If the folders are defined, we use them to reload the certificates during
+     * runtime */
+    UA_String trustListFolder;
+    UA_String issuerListFolder;
+    UA_String revocationListFolder;
+
     mbedtls_x509_crt certificateTrustList;
     mbedtls_x509_crt certificateIssuerList;
     mbedtls_x509_crl certificateRevocationList;
 } CertInfo;
 
+#if __linux__ /* Linux only so far */
+
+#include <dirent.h>
+#include <limits.h>
+
+static UA_StatusCode
+fileNamesFromFolder(const UA_String *folder, size_t *pathsSize, UA_String **paths) {
+    char buf[PATH_MAX + 1];
+    if(folder->length > PATH_MAX)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    memcpy(buf, folder->data, folder->length);
+    buf[folder->length] = 0;
+    
+    DIR *dir = opendir(buf);
+    if(!dir)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    *paths = (UA_String*)UA_Array_new(256, &UA_TYPES[UA_TYPES_STRING]);
+    if(*paths == NULL) {
+        closedir(dir);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    struct dirent *ent;
+    char buf2[PATH_MAX + 1];
+    realpath(buf, buf2);
+    size_t pathlen = strlen(buf2);
+    *pathsSize = 0;
+    while((ent = readdir (dir)) != NULL && *pathsSize < 256) {
+        if(ent->d_type != DT_REG)
+            continue;
+        buf2[pathlen] = '/';
+        buf2[pathlen+1] = 0;
+        strcat(buf2, ent->d_name);
+        (*paths)[*pathsSize] = UA_STRING_ALLOC(buf2);
+        *pathsSize += 1;
+    }
+    closedir(dir);
+
+    if(*pathsSize == 0) {
+        UA_free(*paths);
+        *paths = NULL;
+    }
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+reloadCertificates(CertInfo *ci) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    int err = 0;
+
+    /* Load the trustlists */
+    if(ci->trustListFolder.length > 0) {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the trust-list");
+        mbedtls_x509_crt_free(&ci->certificateTrustList);
+        mbedtls_x509_crt_init(&ci->certificateTrustList);
+
+        char f[PATH_MAX];
+        memcpy(f, ci->trustListFolder.data, ci->trustListFolder.length);
+        f[ci->trustListFolder.length] = 0;
+        err = mbedtls_x509_crt_parse_path(&ci->certificateTrustList, f);
+        if(err == 0) {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Loaded certificate from %s", f);
+        } else {
+            char errBuff[300];
+            mbedtls_strerror(err, errBuff, 300);
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Failed to load certificate from %s", f);
+        }
+    }
+
+    /* Load the revocationlists */
+    if(ci->revocationListFolder.length > 0) {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list");
+        size_t pathsSize = 0;
+        UA_String *paths = NULL;
+        retval = fileNamesFromFolder(&ci->revocationListFolder, &pathsSize, &paths);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        mbedtls_x509_crl_free(&ci->certificateRevocationList);
+        mbedtls_x509_crl_init(&ci->certificateRevocationList);
+        for(size_t i = 0; i < pathsSize; i++) {
+            char f[PATH_MAX];
+            memcpy(f, paths[i].data, paths[i].length);
+            f[paths[i].length] = 0;
+            err = mbedtls_x509_crl_parse_file(&ci->certificateRevocationList, f);
+            if(err == 0) {
+                UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                            "Loaded certificate from %.*s",
+                            (int)paths[i].length, paths[i].data);
+            } else {
+                UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                            "Failed to load certificate from %.*s",
+                            (int)paths[i].length, paths[i].data);
+            }
+        }
+        UA_Array_delete(paths, pathsSize, &UA_TYPES[UA_TYPES_STRING]);
+        paths = NULL;
+        pathsSize = 0;
+    }
+
+    /* Load the issuerlists */
+    if(ci->issuerListFolder.length > 0) {
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list");
+        mbedtls_x509_crt_free(&ci->certificateIssuerList);
+        mbedtls_x509_crt_init(&ci->certificateIssuerList);
+        char f[PATH_MAX];
+        memcpy(f, ci->issuerListFolder.data, ci->issuerListFolder.length);
+        f[ci->issuerListFolder.length] = 0;
+        err = mbedtls_x509_crt_parse_path(&ci->certificateIssuerList, f);
+        if(err == 0) {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Loaded certificate from %s", f);
+        } else {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
+                        "Failed to load certificate from %s", f);
+        }
+    }
+
+    return retval;
+}
+
+#endif
+
 static UA_StatusCode
 certificateVerification_verify(void *verificationContext,
                                const UA_ByteString *certificate) {
@@ -60,6 +196,16 @@ certificateVerification_verify(void *verificationContext,
     if(!ci)
         return UA_STATUSCODE_BADINTERNALERROR;
 
+#if __linux__ /* Reload certificates if folder paths are specified */
+    reloadCertificates(ci);
+#endif
+
+    /* if(ci->certificateTrustList.raw.len == 0) { */
+    /*     UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, */
+    /*                    "No Trustlist loaded. Accepting the certificate."); */
+    /*     return UA_STATUSCODE_GOOD; */
+    /* } */
+
     /* Parse the certificate */
     mbedtls_x509_crt remoteCertificate;
 
@@ -347,6 +493,9 @@ certificateVerification_deleteMembers(UA_CertificateVerification *cv) {
     mbedtls_x509_crt_free(&ci->certificateTrustList);
     mbedtls_x509_crl_free(&ci->certificateRevocationList);
     mbedtls_x509_crt_free(&ci->certificateIssuerList);
+    UA_String_clear(&ci->trustListFolder);
+    UA_String_clear(&ci->issuerListFolder);
+    UA_String_clear(&ci->revocationListFolder);
     UA_free(ci);
     cv->context = NULL;
 }
@@ -362,6 +511,7 @@ UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv,
     CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
     if(!ci)
         return UA_STATUSCODE_BADOUTOFMEMORY;
+    memset(ci, 0, sizeof(CertInfo));
     mbedtls_x509_crt_init(&ci->certificateTrustList);
     mbedtls_x509_crl_init(&ci->certificateRevocationList);
     mbedtls_x509_crt_init(&ci->certificateIssuerList);
@@ -403,4 +553,37 @@ error:
     return UA_STATUSCODE_BADINTERNALERROR;
 }
 
+#if __linux__ /* Linux only so far */
+
+UA_StatusCode
+UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv,
+                                       const char *trustListFolder,
+                                       const char *issuerListFolder,
+                                       const char *revocationListFolder) {
+    CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
+    if(!ci)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    memset(ci, 0, sizeof(CertInfo));
+    mbedtls_x509_crt_init(&ci->certificateTrustList);
+    mbedtls_x509_crl_init(&ci->certificateRevocationList);
+    mbedtls_x509_crt_init(&ci->certificateIssuerList);
+
+    /* Only set the folder paths. They will be reloaded during runtime.
+     * TODO: Add a more efficient reloading of only the changes */
+    ci->trustListFolder = UA_STRING_ALLOC(trustListFolder);
+    ci->issuerListFolder = UA_STRING_ALLOC(issuerListFolder);
+    ci->revocationListFolder = UA_STRING_ALLOC(revocationListFolder);
+
+    reloadCertificates(ci);
+
+    cv->context = (void*)ci;
+    cv->verifyCertificate = certificateVerification_verify;
+    cv->deleteMembers = certificateVerification_deleteMembers;
+    cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+#endif
+
 #endif