ua_pki_default.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  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. */
  7. #include <open62541/plugin/pki_default.h>
  8. #ifdef UA_ENABLE_ENCRYPTION
  9. #include <mbedtls/x509.h>
  10. #include <mbedtls/x509_crt.h>
  11. #endif
  12. #define REMOTECERTIFICATETRUSTED 1
  13. #define ISSUERKNOWN 2
  14. #define DUALPARENT 3
  15. #define PARENTFOUND 4
  16. /************/
  17. /* AllowAll */
  18. /************/
  19. static UA_StatusCode
  20. verifyCertificateAllowAll(void *verificationContext,
  21. const UA_ByteString *certificate) {
  22. return UA_STATUSCODE_GOOD;
  23. }
  24. static UA_StatusCode
  25. verifyApplicationURIAllowAll(void *verificationContext,
  26. const UA_ByteString *certificate,
  27. const UA_String *applicationURI) {
  28. return UA_STATUSCODE_GOOD;
  29. }
  30. static void
  31. deleteVerifyAllowAll(UA_CertificateVerification *cv) {
  32. }
  33. void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) {
  34. cv->verifyCertificate = verifyCertificateAllowAll;
  35. cv->verifyApplicationURI = verifyApplicationURIAllowAll;
  36. cv->deleteMembers = deleteVerifyAllowAll;
  37. }
  38. #ifdef UA_ENABLE_ENCRYPTION
  39. typedef struct {
  40. mbedtls_x509_crt certificateTrustList;
  41. mbedtls_x509_crt certificateIssuerList;
  42. mbedtls_x509_crl certificateRevocationList;
  43. } CertInfo;
  44. static UA_StatusCode
  45. certificateVerification_verify(void *verificationContext,
  46. const UA_ByteString *certificate) {
  47. CertInfo *ci = (CertInfo*)verificationContext;
  48. if(!ci)
  49. return UA_STATUSCODE_BADINTERNALERROR;
  50. /* Parse the certificate */
  51. mbedtls_x509_crt remoteCertificate;
  52. /* Temporary Object to parse the trustList */
  53. mbedtls_x509_crt *tempCert;
  54. /* Temporary Object to parse the revocationList */
  55. mbedtls_x509_crl *tempCrl;
  56. /* Temporary Object to identify the parent CA when there is no intermediate CA */
  57. mbedtls_x509_crt *parentCert;
  58. /* Temporary Object to identify the parent CA when there is intermediate CA */
  59. mbedtls_x509_crt *parentCert_2;
  60. /* Flag value to identify if the issuer certificate is found */
  61. int issuerKnown = 0;
  62. /* Flag value to identify if the parent certificate found */
  63. int parentFound = 0;
  64. mbedtls_x509_crt_init(&remoteCertificate);
  65. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  66. certificate->length);
  67. if(mbedErr) {
  68. /* char errBuff[300]; */
  69. /* mbedtls_strerror(mbedErr, errBuff, 300); */
  70. /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */
  71. /* "Could not parse the remote certificate with error: %s", errBuff); */
  72. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  73. }
  74. /* Verify */
  75. mbedtls_x509_crt_profile crtProfile = {
  76. MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),
  77. 0xFFFFFF, 0x000000, 128 * 8 // in bits
  78. }; // TODO: remove magic numbers
  79. uint32_t flags = 0;
  80. mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
  81. &ci->certificateTrustList,
  82. &ci->certificateRevocationList,
  83. &crtProfile, NULL, &flags, NULL, NULL);
  84. /* Flag to check if the remote certificate is trusted or not */
  85. int TRUSTED = 0;
  86. /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */
  87. if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) {
  88. for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) {
  89. if(remoteCertificate.raw.len == tempCert->raw.len &&
  90. memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) {
  91. TRUSTED = REMOTECERTIFICATETRUSTED;
  92. break;
  93. }
  94. }
  95. }
  96. /* If the remote certificate is present in the trustList then check if the issuer certificate
  97. * of remoteCertificate is present in issuerList */
  98. if(TRUSTED && mbedErr) {
  99. mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
  100. &ci->certificateIssuerList,
  101. &ci->certificateRevocationList,
  102. &crtProfile, NULL, &flags, NULL, NULL);
  103. /* Check if the parent certificate has a CRL file available */
  104. if(!mbedErr) {
  105. /* Flag value to identify if that there is an intermediate CA present */
  106. int dualParent = 0;
  107. /* Identify the topmost parent certificate for the remoteCertificate */
  108. for( parentCert = &ci->certificateIssuerList; parentCert != NULL; parentCert = parentCert->next ) {
  109. if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
  110. for(parentCert_2 = &ci->certificateTrustList; parentCert_2 != NULL; parentCert_2 = parentCert_2->next) {
  111. if(memcmp(parentCert->issuer_raw.p, parentCert_2->subject_raw.p, parentCert_2->subject_raw.len) == 0) {
  112. dualParent = DUALPARENT;
  113. parentFound = PARENTFOUND;
  114. break;
  115. }
  116. }
  117. parentFound = PARENTFOUND;
  118. }
  119. if(parentFound == PARENTFOUND) {
  120. break;
  121. }
  122. }
  123. /* Check if there is an intermediate certificate between the topmost parent
  124. * certificate and child certificate
  125. * If yes the topmost parent certificate is to be checked whether it has a
  126. * CRL file avaiable */
  127. if(dualParent == DUALPARENT && parentFound == PARENTFOUND) {
  128. parentCert = parentCert_2;
  129. }
  130. /* If a parent certificate is found traverse the revocationList and identify
  131. * if there is any CRL file that corresponds to the parentCertificate */
  132. if(parentFound == PARENTFOUND) {
  133. tempCrl = &ci->certificateRevocationList;
  134. while(tempCrl != NULL) {
  135. if(tempCrl->version != 0 &&
  136. tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
  137. memcmp(tempCrl->issuer_raw.p,
  138. parentCert->subject_raw.p,
  139. tempCrl->issuer_raw.len) == 0) {
  140. issuerKnown = ISSUERKNOWN;
  141. break;
  142. }
  143. tempCrl = tempCrl->next;
  144. }
  145. /* If the CRL file corresponding to the parent certificate is not present
  146. * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */
  147. if(!issuerKnown) {
  148. return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
  149. }
  150. }
  151. }
  152. }
  153. else if(!mbedErr && !TRUSTED) {
  154. /* This else if section is to identify if the parent certificate which is present in trustList
  155. * has CRL file corresponding to it */
  156. /* Identify the parent certificate of the remoteCertificate */
  157. for(parentCert = &ci->certificateTrustList; parentCert != NULL; parentCert = parentCert->next) {
  158. if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
  159. parentFound = PARENTFOUND;
  160. break;
  161. }
  162. }
  163. /* If the parent certificate is found traverse the revocationList and identify
  164. * if there is any CRL file that corresponds to the parentCertificate */
  165. if(parentFound == PARENTFOUND &&
  166. memcmp(remoteCertificate.issuer_raw.p, remoteCertificate.subject_raw.p, remoteCertificate.subject_raw.len) != 0) {
  167. tempCrl = &ci->certificateRevocationList;
  168. while(tempCrl != NULL) {
  169. if(tempCrl->version != 0 &&
  170. tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
  171. memcmp(tempCrl->issuer_raw.p,
  172. parentCert->subject_raw.p,
  173. tempCrl->issuer_raw.len) == 0) {
  174. issuerKnown = ISSUERKNOWN;
  175. break;
  176. }
  177. tempCrl = tempCrl->next;
  178. }
  179. /* If the CRL file corresponding to the parent certificate is not present
  180. * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */
  181. if(!issuerKnown) {
  182. return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
  183. }
  184. }
  185. }
  186. // TODO: Extend verification
  187. /* This condition will check whether the certificate is a User certificate
  188. * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and
  189. * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate
  190. * shall be condidered as CA Certificate and cannot be used to establish a
  191. * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js
  192. * for more details */
  193. if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) &&
  194. (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) {
  195. return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
  196. }
  197. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  198. if(mbedErr) {
  199. /* char buff[100]; */
  200. /* mbedtls_x509_crt_verify_info(buff, 100, "", flags); */
  201. /* UA_LOG_ERROR(channelContextData->policyContext->securityPolicy->logger, */
  202. /* UA_LOGCATEGORY_SECURITYPOLICY, */
  203. /* "Verifying the certificate failed with error: %s", buff); */
  204. if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
  205. retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
  206. } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE ||
  207. flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) {
  208. retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID;
  209. } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED ||
  210. flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) {
  211. retval = UA_STATUSCODE_BADCERTIFICATEREVOKED;
  212. } else {
  213. retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  214. }
  215. }
  216. mbedtls_x509_crt_free(&remoteCertificate);
  217. return retval;
  218. }
  219. /* Find binary substring. Taken and adjusted from
  220. * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */
  221. static const unsigned char *
  222. bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
  223. /* find first occurrence of c in char s[] for length l*/
  224. /* handle special case */
  225. if(l == 0)
  226. return (NULL);
  227. for(; *s != ch; ++s, --l)
  228. if(l == 0)
  229. return (NULL);
  230. return s;
  231. }
  232. static const unsigned char *
  233. bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
  234. /* find first occurrence of s2[] in s1[] for length l1*/
  235. const unsigned char *ss1 = s1;
  236. const unsigned char *ss2 = s2;
  237. /* handle special case */
  238. if(l1 == 0)
  239. return (NULL);
  240. if(l2 == 0)
  241. return s1;
  242. /* match prefix */
  243. for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
  244. (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {
  245. /* match rest of prefix */
  246. const unsigned char *sc1, *sc2;
  247. for (sc1 = s1, sc2 = s2; ;)
  248. if (++sc2 >= ss2+l2)
  249. return s1;
  250. else if (*++sc1 != *sc2)
  251. break;
  252. }
  253. return NULL;
  254. }
  255. static UA_StatusCode
  256. certificateVerification_verifyApplicationURI(void *verificationContext,
  257. const UA_ByteString *certificate,
  258. const UA_String *applicationURI) {
  259. CertInfo *ci = (CertInfo*)verificationContext;
  260. if(!ci)
  261. return UA_STATUSCODE_BADINTERNALERROR;
  262. /* Parse the certificate */
  263. mbedtls_x509_crt remoteCertificate;
  264. mbedtls_x509_crt_init(&remoteCertificate);
  265. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  266. certificate->length);
  267. if(mbedErr)
  268. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  269. /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
  270. * of the Alternative Subject Name. Instead test whether the URI-string is
  271. * present in the v3_ext field in general.
  272. *
  273. * TODO: Improve parsing of the Alternative Subject Name */
  274. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  275. if(bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
  276. applicationURI->data, applicationURI->length) == NULL)
  277. retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
  278. mbedtls_x509_crt_free(&remoteCertificate);
  279. return retval;
  280. }
  281. static void
  282. certificateVerification_deleteMembers(UA_CertificateVerification *cv) {
  283. CertInfo *ci = (CertInfo*)cv->context;
  284. if(!ci)
  285. return;
  286. mbedtls_x509_crt_free(&ci->certificateTrustList);
  287. mbedtls_x509_crl_free(&ci->certificateRevocationList);
  288. mbedtls_x509_crt_free(&ci->certificateIssuerList);
  289. UA_free(ci);
  290. cv->context = NULL;
  291. }
  292. UA_StatusCode
  293. UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv,
  294. const UA_ByteString *certificateTrustList,
  295. size_t certificateTrustListSize,
  296. const UA_ByteString *certificateIssuerList,
  297. size_t certificateIssuerListSize,
  298. const UA_ByteString *certificateRevocationList,
  299. size_t certificateRevocationListSize) {
  300. CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
  301. if(!ci)
  302. return UA_STATUSCODE_BADOUTOFMEMORY;
  303. mbedtls_x509_crt_init(&ci->certificateTrustList);
  304. mbedtls_x509_crl_init(&ci->certificateRevocationList);
  305. mbedtls_x509_crt_init(&ci->certificateIssuerList);
  306. cv->context = (void*)ci;
  307. if(certificateTrustListSize > 0)
  308. cv->verifyCertificate = certificateVerification_verify;
  309. else
  310. cv->verifyCertificate = verifyCertificateAllowAll;
  311. cv->deleteMembers = certificateVerification_deleteMembers;
  312. cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
  313. int err = 0;
  314. for(size_t i = 0; i < certificateTrustListSize; i++) {
  315. err = mbedtls_x509_crt_parse(&ci->certificateTrustList,
  316. certificateTrustList[i].data,
  317. certificateTrustList[i].length);
  318. if(err)
  319. goto error;
  320. }
  321. for(size_t i = 0; i < certificateIssuerListSize; i++) {
  322. err = mbedtls_x509_crt_parse(&ci->certificateIssuerList,
  323. certificateIssuerList[i].data,
  324. certificateIssuerList[i].length);
  325. if(err)
  326. goto error;
  327. }
  328. for(size_t i = 0; i < certificateRevocationListSize; i++) {
  329. err = mbedtls_x509_crl_parse(&ci->certificateRevocationList,
  330. certificateRevocationList[i].data,
  331. certificateRevocationList[i].length);
  332. if(err)
  333. goto error;
  334. }
  335. return UA_STATUSCODE_GOOD;
  336. error:
  337. certificateVerification_deleteMembers(cv);
  338. return UA_STATUSCODE_BADINTERNALERROR;
  339. }
  340. #endif