ua_pki_default.c 22 KB

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