ua_pki_default.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  2. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  3. *
  4. * Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
  5. * Copyright 2019 (c) Kalycito Infotech Private Limited
  6. * Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB
  7. */
  8. #include <open62541/server_config.h>
  9. #include <open62541/plugin/pki_default.h>
  10. #include <open62541/plugin/log_stdout.h>
  11. #ifdef UA_ENABLE_ENCRYPTION
  12. #include <mbedtls/x509.h>
  13. #include <mbedtls/x509_crt.h>
  14. #include <mbedtls/error.h>
  15. #endif
  16. #define REMOTECERTIFICATETRUSTED 1
  17. #define ISSUERKNOWN 2
  18. #define DUALPARENT 3
  19. #define PARENTFOUND 4
  20. /************/
  21. /* AllowAll */
  22. /************/
  23. static UA_StatusCode
  24. verifyCertificateAllowAll(void *verificationContext,
  25. const UA_ByteString *certificate) {
  26. return UA_STATUSCODE_GOOD;
  27. }
  28. static UA_StatusCode
  29. verifyApplicationURIAllowAll(void *verificationContext,
  30. const UA_ByteString *certificate,
  31. const UA_String *applicationURI) {
  32. return UA_STATUSCODE_GOOD;
  33. }
  34. static void
  35. clearVerifyAllowAll(UA_CertificateVerification *cv) {
  36. }
  37. void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) {
  38. cv->verifyCertificate = verifyCertificateAllowAll;
  39. cv->verifyApplicationURI = verifyApplicationURIAllowAll;
  40. cv->clear = clearVerifyAllowAll;
  41. }
  42. #ifdef UA_ENABLE_ENCRYPTION
  43. typedef struct {
  44. /* If the folders are defined, we use them to reload the certificates during
  45. * runtime */
  46. UA_String trustListFolder;
  47. UA_String issuerListFolder;
  48. UA_String revocationListFolder;
  49. mbedtls_x509_crt certificateTrustList;
  50. mbedtls_x509_crt certificateIssuerList;
  51. mbedtls_x509_crl certificateRevocationList;
  52. } CertInfo;
  53. #ifdef __linux__ /* Linux only so far */
  54. #include <dirent.h>
  55. #include <limits.h>
  56. static UA_StatusCode
  57. fileNamesFromFolder(const UA_String *folder, size_t *pathsSize, UA_String **paths) {
  58. char buf[PATH_MAX + 1];
  59. if(folder->length > PATH_MAX)
  60. return UA_STATUSCODE_BADINTERNALERROR;
  61. memcpy(buf, folder->data, folder->length);
  62. buf[folder->length] = 0;
  63. DIR *dir = opendir(buf);
  64. if(!dir)
  65. return UA_STATUSCODE_BADINTERNALERROR;
  66. *paths = (UA_String*)UA_Array_new(256, &UA_TYPES[UA_TYPES_STRING]);
  67. if(*paths == NULL) {
  68. closedir(dir);
  69. return UA_STATUSCODE_BADOUTOFMEMORY;
  70. }
  71. struct dirent *ent;
  72. char buf2[PATH_MAX + 1];
  73. char *res = realpath(buf, buf2);
  74. if(!res) {
  75. closedir(dir);
  76. return UA_STATUSCODE_BADINTERNALERROR;
  77. }
  78. size_t pathlen = strlen(buf2);
  79. *pathsSize = 0;
  80. while((ent = readdir (dir)) != NULL && *pathsSize < 256) {
  81. if(ent->d_type != DT_REG)
  82. continue;
  83. buf2[pathlen] = '/';
  84. buf2[pathlen+1] = 0;
  85. strcat(buf2, ent->d_name);
  86. (*paths)[*pathsSize] = UA_STRING_ALLOC(buf2);
  87. *pathsSize += 1;
  88. }
  89. closedir(dir);
  90. if(*pathsSize == 0) {
  91. UA_free(*paths);
  92. *paths = NULL;
  93. }
  94. return UA_STATUSCODE_GOOD;
  95. }
  96. static UA_StatusCode
  97. reloadCertificates(CertInfo *ci) {
  98. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  99. int err = 0;
  100. /* Load the trustlists */
  101. if(ci->trustListFolder.length > 0) {
  102. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the trust-list");
  103. mbedtls_x509_crt_free(&ci->certificateTrustList);
  104. mbedtls_x509_crt_init(&ci->certificateTrustList);
  105. char f[PATH_MAX];
  106. memcpy(f, ci->trustListFolder.data, ci->trustListFolder.length);
  107. f[ci->trustListFolder.length] = 0;
  108. err = mbedtls_x509_crt_parse_path(&ci->certificateTrustList, f);
  109. if(err == 0) {
  110. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  111. "Loaded certificate from %s", f);
  112. } else {
  113. char errBuff[300];
  114. mbedtls_strerror(err, errBuff, 300);
  115. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  116. "Failed to load certificate from %s", f);
  117. }
  118. }
  119. /* Load the revocationlists */
  120. if(ci->revocationListFolder.length > 0) {
  121. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list");
  122. size_t pathsSize = 0;
  123. UA_String *paths = NULL;
  124. retval = fileNamesFromFolder(&ci->revocationListFolder, &pathsSize, &paths);
  125. if(retval != UA_STATUSCODE_GOOD)
  126. return retval;
  127. mbedtls_x509_crl_free(&ci->certificateRevocationList);
  128. mbedtls_x509_crl_init(&ci->certificateRevocationList);
  129. for(size_t i = 0; i < pathsSize; i++) {
  130. char f[PATH_MAX];
  131. memcpy(f, paths[i].data, paths[i].length);
  132. f[paths[i].length] = 0;
  133. err = mbedtls_x509_crl_parse_file(&ci->certificateRevocationList, f);
  134. if(err == 0) {
  135. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  136. "Loaded certificate from %.*s",
  137. (int)paths[i].length, paths[i].data);
  138. } else {
  139. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  140. "Failed to load certificate from %.*s",
  141. (int)paths[i].length, paths[i].data);
  142. }
  143. }
  144. UA_Array_delete(paths, pathsSize, &UA_TYPES[UA_TYPES_STRING]);
  145. paths = NULL;
  146. pathsSize = 0;
  147. }
  148. /* Load the issuerlists */
  149. if(ci->issuerListFolder.length > 0) {
  150. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list");
  151. mbedtls_x509_crt_free(&ci->certificateIssuerList);
  152. mbedtls_x509_crt_init(&ci->certificateIssuerList);
  153. char f[PATH_MAX];
  154. memcpy(f, ci->issuerListFolder.data, ci->issuerListFolder.length);
  155. f[ci->issuerListFolder.length] = 0;
  156. err = mbedtls_x509_crt_parse_path(&ci->certificateIssuerList, f);
  157. if(err == 0) {
  158. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  159. "Loaded certificate from %s", f);
  160. } else {
  161. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
  162. "Failed to load certificate from %s", f);
  163. }
  164. }
  165. return retval;
  166. }
  167. #endif
  168. static UA_StatusCode
  169. certificateVerification_verify(void *verificationContext,
  170. const UA_ByteString *certificate) {
  171. CertInfo *ci = (CertInfo*)verificationContext;
  172. if(!ci)
  173. return UA_STATUSCODE_BADINTERNALERROR;
  174. #ifdef __linux__ /* Reload certificates if folder paths are specified */
  175. reloadCertificates(ci);
  176. #endif
  177. /* if(ci->certificateTrustList.raw.len == 0) { */
  178. /* UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, */
  179. /* "No Trustlist loaded. Accepting the certificate."); */
  180. /* return UA_STATUSCODE_GOOD; */
  181. /* } */
  182. /* Parse the certificate */
  183. mbedtls_x509_crt remoteCertificate;
  184. /* Temporary Object to parse the trustList */
  185. mbedtls_x509_crt *tempCert;
  186. /* Temporary Object to parse the revocationList */
  187. mbedtls_x509_crl *tempCrl;
  188. /* Temporary Object to identify the parent CA when there is no intermediate CA */
  189. mbedtls_x509_crt *parentCert;
  190. /* Temporary Object to identify the parent CA when there is intermediate CA */
  191. mbedtls_x509_crt *parentCert_2;
  192. /* Flag value to identify if the issuer certificate is found */
  193. int issuerKnown = 0;
  194. /* Flag value to identify if the parent certificate found */
  195. int parentFound = 0;
  196. mbedtls_x509_crt_init(&remoteCertificate);
  197. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  198. certificate->length);
  199. if(mbedErr) {
  200. /* char errBuff[300]; */
  201. /* mbedtls_strerror(mbedErr, errBuff, 300); */
  202. /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */
  203. /* "Could not parse the remote certificate with error: %s", errBuff); */
  204. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  205. }
  206. /* Verify */
  207. mbedtls_x509_crt_profile crtProfile = {
  208. MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),
  209. 0xFFFFFF, 0x000000, 128 * 8 // in bits
  210. }; // TODO: remove magic numbers
  211. uint32_t flags = 0;
  212. mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
  213. &ci->certificateTrustList,
  214. &ci->certificateRevocationList,
  215. &crtProfile, NULL, &flags, NULL, NULL);
  216. /* Flag to check if the remote certificate is trusted or not */
  217. int TRUSTED = 0;
  218. /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */
  219. if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) {
  220. for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) {
  221. if(remoteCertificate.raw.len == tempCert->raw.len &&
  222. memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) {
  223. TRUSTED = REMOTECERTIFICATETRUSTED;
  224. break;
  225. }
  226. }
  227. }
  228. /* If the remote certificate is present in the trustList then check if the issuer certificate
  229. * of remoteCertificate is present in issuerList */
  230. if(TRUSTED && mbedErr) {
  231. mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
  232. &ci->certificateIssuerList,
  233. &ci->certificateRevocationList,
  234. &crtProfile, NULL, &flags, NULL, NULL);
  235. /* Check if the parent certificate has a CRL file available */
  236. if(!mbedErr) {
  237. /* Flag value to identify if that there is an intermediate CA present */
  238. int dualParent = 0;
  239. /* Identify the topmost parent certificate for the remoteCertificate */
  240. for( parentCert = &ci->certificateIssuerList; parentCert != NULL; parentCert = parentCert->next ) {
  241. if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
  242. for(parentCert_2 = &ci->certificateTrustList; parentCert_2 != NULL; parentCert_2 = parentCert_2->next) {
  243. if(memcmp(parentCert->issuer_raw.p, parentCert_2->subject_raw.p, parentCert_2->subject_raw.len) == 0) {
  244. dualParent = DUALPARENT;
  245. parentFound = PARENTFOUND;
  246. break;
  247. }
  248. }
  249. parentFound = PARENTFOUND;
  250. }
  251. if(parentFound == PARENTFOUND) {
  252. break;
  253. }
  254. }
  255. /* Check if there is an intermediate certificate between the topmost parent
  256. * certificate and child certificate
  257. * If yes the topmost parent certificate is to be checked whether it has a
  258. * CRL file avaiable */
  259. if(dualParent == DUALPARENT && parentFound == PARENTFOUND) {
  260. parentCert = parentCert_2;
  261. }
  262. /* If a parent certificate is found traverse the revocationList and identify
  263. * if there is any CRL file that corresponds to the parentCertificate */
  264. if(parentFound == PARENTFOUND) {
  265. tempCrl = &ci->certificateRevocationList;
  266. while(tempCrl != NULL) {
  267. if(tempCrl->version != 0 &&
  268. tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
  269. memcmp(tempCrl->issuer_raw.p,
  270. parentCert->subject_raw.p,
  271. tempCrl->issuer_raw.len) == 0) {
  272. issuerKnown = ISSUERKNOWN;
  273. break;
  274. }
  275. tempCrl = tempCrl->next;
  276. }
  277. /* If the CRL file corresponding to the parent certificate is not present
  278. * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */
  279. if(!issuerKnown) {
  280. return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
  281. }
  282. }
  283. }
  284. }
  285. else if(!mbedErr && !TRUSTED) {
  286. /* This else if section is to identify if the parent certificate which is present in trustList
  287. * has CRL file corresponding to it */
  288. /* Identify the parent certificate of the remoteCertificate */
  289. for(parentCert = &ci->certificateTrustList; parentCert != NULL; parentCert = parentCert->next) {
  290. if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
  291. parentFound = PARENTFOUND;
  292. break;
  293. }
  294. }
  295. /* If the parent certificate is found traverse the revocationList and identify
  296. * if there is any CRL file that corresponds to the parentCertificate */
  297. if(parentFound == PARENTFOUND &&
  298. memcmp(remoteCertificate.issuer_raw.p, remoteCertificate.subject_raw.p, remoteCertificate.subject_raw.len) != 0) {
  299. tempCrl = &ci->certificateRevocationList;
  300. while(tempCrl != NULL) {
  301. if(tempCrl->version != 0 &&
  302. tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
  303. memcmp(tempCrl->issuer_raw.p,
  304. parentCert->subject_raw.p,
  305. tempCrl->issuer_raw.len) == 0) {
  306. issuerKnown = ISSUERKNOWN;
  307. break;
  308. }
  309. tempCrl = tempCrl->next;
  310. }
  311. /* If the CRL file corresponding to the parent certificate is not present
  312. * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */
  313. if(!issuerKnown) {
  314. return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
  315. }
  316. }
  317. }
  318. // TODO: Extend verification
  319. /* This condition will check whether the certificate is a User certificate
  320. * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and
  321. * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate
  322. * shall be condidered as CA Certificate and cannot be used to establish a
  323. * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js
  324. * for more details */
  325. if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) &&
  326. (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) {
  327. return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
  328. }
  329. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  330. if(mbedErr) {
  331. /* char buff[100]; */
  332. /* mbedtls_x509_crt_verify_info(buff, 100, "", flags); */
  333. /* UA_LOG_ERROR(channelContextData->policyContext->securityPolicy->logger, */
  334. /* UA_LOGCATEGORY_SECURITYPOLICY, */
  335. /* "Verifying the certificate failed with error: %s", buff); */
  336. if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
  337. retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
  338. } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE ||
  339. flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) {
  340. retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID;
  341. } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED ||
  342. flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) {
  343. retval = UA_STATUSCODE_BADCERTIFICATEREVOKED;
  344. } else {
  345. retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  346. }
  347. }
  348. mbedtls_x509_crt_free(&remoteCertificate);
  349. return retval;
  350. }
  351. /* Find binary substring. Taken and adjusted from
  352. * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */
  353. static const unsigned char *
  354. bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
  355. /* find first occurrence of c in char s[] for length l*/
  356. /* handle special case */
  357. if(l == 0)
  358. return (NULL);
  359. for(; *s != ch; ++s, --l)
  360. if(l == 0)
  361. return (NULL);
  362. return s;
  363. }
  364. static const unsigned char *
  365. bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
  366. /* find first occurrence of s2[] in s1[] for length l1*/
  367. const unsigned char *ss1 = s1;
  368. const unsigned char *ss2 = s2;
  369. /* handle special case */
  370. if(l1 == 0)
  371. return (NULL);
  372. if(l2 == 0)
  373. return s1;
  374. /* match prefix */
  375. for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
  376. (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {
  377. /* match rest of prefix */
  378. const unsigned char *sc1, *sc2;
  379. for (sc1 = s1, sc2 = s2; ;)
  380. if (++sc2 >= ss2+l2)
  381. return s1;
  382. else if (*++sc1 != *sc2)
  383. break;
  384. }
  385. return NULL;
  386. }
  387. static UA_StatusCode
  388. certificateVerification_verifyApplicationURI(void *verificationContext,
  389. const UA_ByteString *certificate,
  390. const UA_String *applicationURI) {
  391. CertInfo *ci = (CertInfo*)verificationContext;
  392. if(!ci)
  393. return UA_STATUSCODE_BADINTERNALERROR;
  394. /* Parse the certificate */
  395. mbedtls_x509_crt remoteCertificate;
  396. mbedtls_x509_crt_init(&remoteCertificate);
  397. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  398. certificate->length);
  399. if(mbedErr)
  400. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  401. /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
  402. * of the Alternative Subject Name. Instead test whether the URI-string is
  403. * present in the v3_ext field in general.
  404. *
  405. * TODO: Improve parsing of the Alternative Subject Name */
  406. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  407. if(bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
  408. applicationURI->data, applicationURI->length) == NULL)
  409. retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
  410. mbedtls_x509_crt_free(&remoteCertificate);
  411. return retval;
  412. }
  413. static void
  414. certificateVerification_clear(UA_CertificateVerification *cv) {
  415. CertInfo *ci = (CertInfo*)cv->context;
  416. if(!ci)
  417. return;
  418. mbedtls_x509_crt_free(&ci->certificateTrustList);
  419. mbedtls_x509_crl_free(&ci->certificateRevocationList);
  420. mbedtls_x509_crt_free(&ci->certificateIssuerList);
  421. UA_String_clear(&ci->trustListFolder);
  422. UA_String_clear(&ci->issuerListFolder);
  423. UA_String_clear(&ci->revocationListFolder);
  424. UA_free(ci);
  425. cv->context = NULL;
  426. }
  427. UA_StatusCode
  428. UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv,
  429. const UA_ByteString *certificateTrustList,
  430. size_t certificateTrustListSize,
  431. const UA_ByteString *certificateIssuerList,
  432. size_t certificateIssuerListSize,
  433. const UA_ByteString *certificateRevocationList,
  434. size_t certificateRevocationListSize) {
  435. CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
  436. if(!ci)
  437. return UA_STATUSCODE_BADOUTOFMEMORY;
  438. memset(ci, 0, sizeof(CertInfo));
  439. mbedtls_x509_crt_init(&ci->certificateTrustList);
  440. mbedtls_x509_crl_init(&ci->certificateRevocationList);
  441. mbedtls_x509_crt_init(&ci->certificateIssuerList);
  442. cv->context = (void*)ci;
  443. if(certificateTrustListSize > 0)
  444. cv->verifyCertificate = certificateVerification_verify;
  445. else
  446. cv->verifyCertificate = verifyCertificateAllowAll;
  447. cv->clear = certificateVerification_clear;
  448. cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
  449. int err = 0;
  450. for(size_t i = 0; i < certificateTrustListSize; i++) {
  451. err = mbedtls_x509_crt_parse(&ci->certificateTrustList,
  452. certificateTrustList[i].data,
  453. certificateTrustList[i].length);
  454. if(err)
  455. goto error;
  456. }
  457. for(size_t i = 0; i < certificateIssuerListSize; i++) {
  458. err = mbedtls_x509_crt_parse(&ci->certificateIssuerList,
  459. certificateIssuerList[i].data,
  460. certificateIssuerList[i].length);
  461. if(err)
  462. goto error;
  463. }
  464. for(size_t i = 0; i < certificateRevocationListSize; i++) {
  465. err = mbedtls_x509_crl_parse(&ci->certificateRevocationList,
  466. certificateRevocationList[i].data,
  467. certificateRevocationList[i].length);
  468. if(err)
  469. goto error;
  470. }
  471. return UA_STATUSCODE_GOOD;
  472. error:
  473. certificateVerification_clear(cv);
  474. return UA_STATUSCODE_BADINTERNALERROR;
  475. }
  476. #ifdef __linux__ /* Linux only so far */
  477. UA_StatusCode
  478. UA_CertificateVerification_CertFolders(UA_CertificateVerification *cv,
  479. const char *trustListFolder,
  480. const char *issuerListFolder,
  481. const char *revocationListFolder) {
  482. CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
  483. if(!ci)
  484. return UA_STATUSCODE_BADOUTOFMEMORY;
  485. memset(ci, 0, sizeof(CertInfo));
  486. mbedtls_x509_crt_init(&ci->certificateTrustList);
  487. mbedtls_x509_crl_init(&ci->certificateRevocationList);
  488. mbedtls_x509_crt_init(&ci->certificateIssuerList);
  489. /* Only set the folder paths. They will be reloaded during runtime.
  490. * TODO: Add a more efficient reloading of only the changes */
  491. ci->trustListFolder = UA_STRING_ALLOC(trustListFolder);
  492. ci->issuerListFolder = UA_STRING_ALLOC(issuerListFolder);
  493. ci->revocationListFolder = UA_STRING_ALLOC(revocationListFolder);
  494. reloadCertificates(ci);
  495. cv->context = (void*)ci;
  496. cv->verifyCertificate = certificateVerification_verify;
  497. cv->clear = certificateVerification_clear;
  498. cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
  499. return UA_STATUSCODE_GOOD;
  500. }
  501. #endif
  502. #endif