ua_pki_certificate.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. */
  6. #include "ua_pki_certificate.h"
  7. #ifdef UA_ENABLE_ENCRYPTION
  8. #include <mbedtls/x509.h>
  9. #include <mbedtls/x509_crt.h>
  10. #endif
  11. /************/
  12. /* AllowAll */
  13. /************/
  14. static UA_StatusCode
  15. verifyCertificateAllowAll(void *verificationContext,
  16. const UA_ByteString *certificate) {
  17. return UA_STATUSCODE_GOOD;
  18. }
  19. static UA_StatusCode
  20. verifyApplicationURIAllowAll(void *verificationContext,
  21. const UA_ByteString *certificate,
  22. const UA_String *applicationURI) {
  23. return UA_STATUSCODE_GOOD;
  24. }
  25. static void
  26. deleteVerifyAllowAll(UA_CertificateVerification *cv) {
  27. }
  28. void UA_CertificateVerification_AcceptAll(UA_CertificateVerification *cv) {
  29. cv->verifyCertificate = verifyCertificateAllowAll;
  30. cv->verifyApplicationURI = verifyApplicationURIAllowAll;
  31. cv->deleteMembers = deleteVerifyAllowAll;
  32. }
  33. #ifdef UA_ENABLE_ENCRYPTION
  34. typedef struct {
  35. mbedtls_x509_crt certificateTrustList;
  36. mbedtls_x509_crl certificateRevocationList;
  37. } CertInfo;
  38. static UA_StatusCode
  39. certificateVerification_verify(void *verificationContext,
  40. const UA_ByteString *certificate) {
  41. CertInfo *ci = (CertInfo*)verificationContext;
  42. if(!ci)
  43. return UA_STATUSCODE_BADINTERNALERROR;
  44. /* Parse the certificate */
  45. mbedtls_x509_crt remoteCertificate;
  46. mbedtls_x509_crt_init(&remoteCertificate);
  47. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  48. certificate->length);
  49. if(mbedErr) {
  50. /* char errBuff[300]; */
  51. /* mbedtls_strerror(mbedErr, errBuff, 300); */
  52. /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */
  53. /* "Could not parse the remote certificate with error: %s", errBuff); */
  54. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  55. }
  56. /* Verify */
  57. mbedtls_x509_crt_profile crtProfile = {
  58. MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),
  59. 0xFFFFFF, 0x000000, 128 * 8 // in bits
  60. }; // TODO: remove magic numbers
  61. uint32_t flags = 0;
  62. mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
  63. &ci->certificateTrustList,
  64. &ci->certificateRevocationList,
  65. &crtProfile, NULL, &flags, NULL, NULL);
  66. // TODO: Extend verification
  67. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  68. if(mbedErr) {
  69. /* char buff[100]; */
  70. /* mbedtls_x509_crt_verify_info(buff, 100, "", flags); */
  71. /* UA_LOG_ERROR(channelContextData->policyContext->securityPolicy->logger, */
  72. /* UA_LOGCATEGORY_SECURITYPOLICY, */
  73. /* "Verifying the certificate failed with error: %s", buff); */
  74. if(flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
  75. retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
  76. } else if (flags & MBEDTLS_X509_BADCERT_FUTURE ||
  77. flags & MBEDTLS_X509_BADCERT_EXPIRED) {
  78. retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID;
  79. } else if(flags & MBEDTLS_X509_BADCERT_REVOKED ||
  80. flags & MBEDTLS_X509_BADCRL_EXPIRED) {
  81. retval = UA_STATUSCODE_BADCERTIFICATEREVOKED;
  82. } else {
  83. retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  84. }
  85. }
  86. mbedtls_x509_crt_free(&remoteCertificate);
  87. return retval;
  88. }
  89. /* Find binary substring. Taken and adjusted from
  90. * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */
  91. static const unsigned char *
  92. bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
  93. /* find first occurrence of c in char s[] for length l*/
  94. /* handle special case */
  95. if(l == 0)
  96. return (NULL);
  97. for(; *s != ch; ++s, --l)
  98. if(l == 0)
  99. return (NULL);
  100. return s;
  101. }
  102. static const unsigned char *
  103. bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
  104. /* find first occurrence of s2[] in s1[] for length l1*/
  105. const unsigned char *ss1 = s1;
  106. const unsigned char *ss2 = s2;
  107. /* handle special case */
  108. if(l1 == 0)
  109. return (NULL);
  110. if(l2 == 0)
  111. return s1;
  112. /* match prefix */
  113. for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
  114. (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {
  115. /* match rest of prefix */
  116. const unsigned char *sc1, *sc2;
  117. for (sc1 = s1, sc2 = s2; ;)
  118. if (++sc2 >= ss2+l2)
  119. return s1;
  120. else if (*++sc1 != *sc2)
  121. break;
  122. }
  123. return NULL;
  124. }
  125. static UA_StatusCode
  126. certificateVerification_verifyApplicationURI(void *verificationContext,
  127. const UA_ByteString *certificate,
  128. const UA_String *applicationURI) {
  129. CertInfo *ci = (CertInfo*)verificationContext;
  130. if(!ci)
  131. return UA_STATUSCODE_BADINTERNALERROR;
  132. /* Parse the certificate */
  133. mbedtls_x509_crt remoteCertificate;
  134. mbedtls_x509_crt_init(&remoteCertificate);
  135. int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
  136. certificate->length);
  137. if(mbedErr)
  138. return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
  139. /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
  140. * of the Alternative Subject Name. Instead test whether the URI-string is
  141. * present in the v3_ext field in general.
  142. *
  143. * TODO: Improve parsing of the Alternative Subject Name */
  144. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  145. if(bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
  146. applicationURI->data, applicationURI->length) == NULL)
  147. retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
  148. mbedtls_x509_crt_free(&remoteCertificate);
  149. return retval;
  150. }
  151. static void
  152. certificateVerification_deleteMembers(UA_CertificateVerification *cv) {
  153. CertInfo *ci = (CertInfo*)cv->context;
  154. if(!ci)
  155. return;
  156. mbedtls_x509_crt_free(&ci->certificateTrustList);
  157. mbedtls_x509_crl_free(&ci->certificateRevocationList);
  158. UA_free(ci);
  159. cv->context = NULL;
  160. }
  161. UA_StatusCode
  162. UA_CertificateVerification_Trustlist(UA_CertificateVerification *cv,
  163. const UA_ByteString *certificateTrustList,
  164. size_t certificateTrustListSize,
  165. const UA_ByteString *certificateRevocationList,
  166. size_t certificateRevocationListSize) {
  167. CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
  168. if(!ci)
  169. return UA_STATUSCODE_BADOUTOFMEMORY;
  170. mbedtls_x509_crt_init(&ci->certificateTrustList);
  171. mbedtls_x509_crl_init(&ci->certificateRevocationList);
  172. cv->context = (void*)ci;
  173. if(certificateTrustListSize > 0)
  174. cv->verifyCertificate = certificateVerification_verify;
  175. else
  176. cv->verifyCertificate = verifyCertificateAllowAll;
  177. cv->deleteMembers = certificateVerification_deleteMembers;
  178. cv->verifyApplicationURI = certificateVerification_verifyApplicationURI;
  179. int err = 0;
  180. for(size_t i = 0; i < certificateTrustListSize; i++) {
  181. err |= mbedtls_x509_crt_parse(&ci->certificateTrustList,
  182. certificateTrustList[i].data,
  183. certificateTrustList[i].length);
  184. }
  185. for(size_t i = 0; i < certificateRevocationListSize; i++) {
  186. err |= mbedtls_x509_crl_parse(&ci->certificateRevocationList,
  187. certificateRevocationList[i].data,
  188. certificateRevocationList[i].length);
  189. }
  190. if(err) {
  191. certificateVerification_deleteMembers(cv);
  192. return UA_STATUSCODE_BADINTERNALERROR;
  193. }
  194. return UA_STATUSCODE_GOOD;
  195. }
  196. #endif