ua_pki_default.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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. /* Flag value to identify if that there is an intermediate CA present */
  65. int dualParent = 0;
  66. mbedtls_x509_crt_init(&remoteCertificate);
  67. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  68. certificate->length);
  69. if(mbedErr) {
  70. /* char errBuff[300]; */
  71. /* mbedtls_strerror(mbedErr, errBuff, 300); */
  72. /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */
  73. /* "Could not parse the remote certificate with error: %s", errBuff); */
  74. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  75. }
  76. /* Verify */
  77. mbedtls_x509_crt_profile crtProfile = {
  78. MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),
  79. 0xFFFFFF, 0x000000, 128 * 8 // in bits
  80. }; // TODO: remove magic numbers
  81. uint32_t flags = 0;
  82. mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
  83. &ci->certificateTrustList,
  84. &ci->certificateRevocationList,
  85. &crtProfile, NULL, &flags, NULL, NULL);
  86. /* Flag to check if the remote certificate is trusted or not */
  87. int TRUSTED = 0;
  88. /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */
  89. if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) {
  90. for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) {
  91. if(remoteCertificate.raw.len == tempCert->raw.len &&
  92. memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) {
  93. TRUSTED = REMOTECERTIFICATETRUSTED;
  94. break;
  95. }
  96. }
  97. }
  98. /* If the remote certificate is present in the trustList then check if the issuer certificate
  99. * of remoteCertificate is present in issuerList */
  100. if(TRUSTED && mbedErr) {
  101. mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
  102. &ci->certificateIssuerList,
  103. &ci->certificateRevocationList,
  104. &crtProfile, NULL, &flags, NULL, NULL);
  105. /* Check if the parent certificate has a CRL file available */
  106. if(!mbedErr) {
  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. // TODO: Extend verification
  154. /* This condition will check whether the certificate is a User certificate
  155. * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and
  156. * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate
  157. * shall be condidered as CA Certificate and cannot be used to establish a
  158. * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js
  159. * for more details */
  160. if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) &&
  161. (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) {
  162. return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
  163. }
  164. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  165. if(mbedErr) {
  166. /* char buff[100]; */
  167. /* mbedtls_x509_crt_verify_info(buff, 100, "", flags); */
  168. /* UA_LOG_ERROR(channelContextData->policyContext->securityPolicy->logger, */
  169. /* UA_LOGCATEGORY_SECURITYPOLICY, */
  170. /* "Verifying the certificate failed with error: %s", buff); */
  171. if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
  172. retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
  173. } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE ||
  174. flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) {
  175. retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID;
  176. } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED ||
  177. flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) {
  178. retval = UA_STATUSCODE_BADCERTIFICATEREVOKED;
  179. } else {
  180. retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  181. }
  182. }
  183. mbedtls_x509_crt_free(&remoteCertificate);
  184. return retval;
  185. }
  186. /* Find binary substring. Taken and adjusted from
  187. * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */
  188. static const unsigned char *
  189. bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
  190. /* find first occurrence of c in char s[] for length l*/
  191. /* handle special case */
  192. if(l == 0)
  193. return (NULL);
  194. for(; *s != ch; ++s, --l)
  195. if(l == 0)
  196. return (NULL);
  197. return s;
  198. }
  199. static const unsigned char *
  200. bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
  201. /* find first occurrence of s2[] in s1[] for length l1*/
  202. const unsigned char *ss1 = s1;
  203. const unsigned char *ss2 = s2;
  204. /* handle special case */
  205. if(l1 == 0)
  206. return (NULL);
  207. if(l2 == 0)
  208. return s1;
  209. /* match prefix */
  210. for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
  211. (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {
  212. /* match rest of prefix */
  213. const unsigned char *sc1, *sc2;
  214. for (sc1 = s1, sc2 = s2; ;)
  215. if (++sc2 >= ss2+l2)
  216. return s1;
  217. else if (*++sc1 != *sc2)
  218. break;
  219. }
  220. return NULL;
  221. }
  222. static UA_StatusCode
  223. certificateVerification_verifyApplicationURI(void *verificationContext,
  224. const UA_ByteString *certificate,
  225. const UA_String *applicationURI) {
  226. CertInfo *ci = (CertInfo*)verificationContext;
  227. if(!ci)
  228. return UA_STATUSCODE_BADINTERNALERROR;
  229. /* Parse the certificate */
  230. mbedtls_x509_crt remoteCertificate;
  231. mbedtls_x509_crt_init(&remoteCertificate);
  232. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  233. certificate->length);
  234. if(mbedErr)
  235. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  236. /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
  237. * of the Alternative Subject Name. Instead test whether the URI-string is
  238. * present in the v3_ext field in general.
  239. *
  240. * TODO: Improve parsing of the Alternative Subject Name */
  241. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  242. if(bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
  243. applicationURI->data, applicationURI->length) == NULL)
  244. retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
  245. mbedtls_x509_crt_free(&remoteCertificate);
  246. return retval;
  247. }
  248. static void
  249. certificateVerification_deleteMembers(UA_CertificateVerification *cv) {
  250. CertInfo *ci = (CertInfo*)cv->context;
  251. if(!ci)
  252. return;
  253. mbedtls_x509_crt_free(&ci->certificateTrustList);
  254. mbedtls_x509_crl_free(&ci->certificateRevocationList);
  255. UA_free(ci);
  256. cv->context = NULL;
  257. }
  258. UA_StatusCode
  259. UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv,
  260. const UA_ByteString *certificateTrustList,
  261. size_t certificateTrustListSize,
  262. const UA_ByteString *certificateIssuerList,
  263. size_t certificateIssuerListSize,
  264. const UA_ByteString *certificateRevocationList,
  265. size_t certificateRevocationListSize) {
  266. CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
  267. if(!ci)
  268. return UA_STATUSCODE_BADOUTOFMEMORY;
  269. mbedtls_x509_crt_init(&ci->certificateTrustList);
  270. mbedtls_x509_crl_init(&ci->certificateRevocationList);
  271. mbedtls_x509_crt_init(&ci->certificateIssuerList);
  272. cv->context = (void*)ci;
  273. if(certificateTrustListSize > 0)
  274. cv->verifyCertificate = certificateVerification_verify;
  275. else
  276. cv->verifyCertificate = verifyCertificateAllowAll;
  277. cv->deleteMembers = certificateVerification_deleteMembers;
  278. cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
  279. int err = 0;
  280. for(size_t i = 0; i < certificateTrustListSize; i++) {
  281. err = mbedtls_x509_crt_parse(&ci->certificateTrustList,
  282. certificateTrustList[i].data,
  283. certificateTrustList[i].length);
  284. if(err)
  285. goto error;
  286. }
  287. for(size_t i = 0; i < certificateIssuerListSize; i++) {
  288. err = mbedtls_x509_crt_parse(&ci->certificateIssuerList,
  289. certificateIssuerList[i].data,
  290. certificateIssuerList[i].length);
  291. if(err)
  292. goto error;
  293. }
  294. for(size_t i = 0; i < certificateRevocationListSize; i++) {
  295. err = mbedtls_x509_crl_parse(&ci->certificateRevocationList,
  296. certificateRevocationList[i].data,
  297. certificateRevocationList[i].length);
  298. if(err)
  299. goto error;
  300. }
  301. return UA_STATUSCODE_GOOD;
  302. error:
  303. certificateVerification_deleteMembers(cv);
  304. return UA_STATUSCODE_BADINTERNALERROR;
  305. }
  306. #endif