openssl_platform_init.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/cal/cal.h>
  6. #include <aws/common/allocator.h>
  7. #include <aws/common/logging.h>
  8. #include <aws/common/mutex.h>
  9. #include <aws/common/thread.h>
  10. #include <dlfcn.h>
  11. #include <aws/cal/private/opensslcrypto_common.h>
  12. static struct openssl_hmac_ctx_table hmac_ctx_table;
  13. static struct openssl_evp_md_ctx_table evp_md_ctx_table;
  14. struct openssl_hmac_ctx_table *g_aws_openssl_hmac_ctx_table = NULL;
  15. struct openssl_evp_md_ctx_table *g_aws_openssl_evp_md_ctx_table = NULL;
  16. static struct aws_allocator *s_libcrypto_allocator = NULL;
  17. /* weak refs to libcrypto functions to force them to at least try to link
  18. * and avoid dead-stripping
  19. */
  20. #if defined(OPENSSL_IS_AWSLC)
  21. extern HMAC_CTX *HMAC_CTX_new(void) __attribute__((weak, used));
  22. extern void HMAC_CTX_free(HMAC_CTX *) __attribute__((weak, used));
  23. extern void HMAC_CTX_reset(HMAC_CTX *) __attribute__((weak, used));
  24. extern void HMAC_CTX_init(HMAC_CTX *) __attribute__((weak, used));
  25. extern void HMAC_CTX_cleanup(HMAC_CTX *) __attribute__((weak, used));
  26. extern int HMAC_Update(HMAC_CTX *, const unsigned char *, size_t) __attribute__((weak, used));
  27. extern int HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *) __attribute__((weak, used));
  28. extern int HMAC_Init_ex(HMAC_CTX *, const void *, size_t, const EVP_MD *, ENGINE *) __attribute__((weak, used));
  29. #else
  30. /* 1.1 */
  31. extern HMAC_CTX *HMAC_CTX_new(void) __attribute__((weak, used));
  32. extern void HMAC_CTX_free(HMAC_CTX *) __attribute__((weak, used));
  33. extern int HMAC_CTX_reset(HMAC_CTX *) __attribute__((weak, used));
  34. /* 1.0.2 */
  35. extern void HMAC_CTX_init(HMAC_CTX *) __attribute__((weak, used));
  36. extern void HMAC_CTX_cleanup(HMAC_CTX *) __attribute__((weak, used));
  37. /* common */
  38. extern int HMAC_Update(HMAC_CTX *, const unsigned char *, size_t) __attribute__((weak, used));
  39. extern int HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *) __attribute__((weak, used));
  40. extern int HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, ENGINE *) __attribute__((weak, used));
  41. /* libcrypto 1.1 stub for init */
  42. static void s_hmac_ctx_init_noop(HMAC_CTX *ctx) {
  43. (void)ctx;
  44. }
  45. /* libcrypto 1.1 stub for clean_up */
  46. static void s_hmac_ctx_clean_up_noop(HMAC_CTX *ctx) {
  47. (void)ctx;
  48. }
  49. /* libcrypto 1.0 shim for new */
  50. static HMAC_CTX *s_hmac_ctx_new(void) {
  51. AWS_PRECONDITION(
  52. g_aws_openssl_hmac_ctx_table->init_fn != s_hmac_ctx_init_noop &&
  53. "libcrypto 1.0 init called on libcrypto 1.1 vtable");
  54. HMAC_CTX *ctx = aws_mem_calloc(s_libcrypto_allocator, 1, 300);
  55. AWS_FATAL_ASSERT(ctx && "Unable to allocate to HMAC_CTX");
  56. g_aws_openssl_hmac_ctx_table->init_fn(ctx);
  57. return ctx;
  58. }
  59. /* libcrypto 1.0 shim for free */
  60. static void s_hmac_ctx_free(HMAC_CTX *ctx) {
  61. AWS_PRECONDITION(ctx);
  62. AWS_PRECONDITION(
  63. g_aws_openssl_hmac_ctx_table->clean_up_fn != s_hmac_ctx_clean_up_noop &&
  64. "libcrypto 1.0 clean_up called on libcrypto 1.1 vtable");
  65. g_aws_openssl_hmac_ctx_table->clean_up_fn(ctx);
  66. aws_mem_release(s_libcrypto_allocator, ctx);
  67. }
  68. /* libcrypto 1.0 shim for reset, matches HMAC_CTX_reset semantics */
  69. static int s_hmac_ctx_reset(HMAC_CTX *ctx) {
  70. AWS_PRECONDITION(ctx);
  71. AWS_PRECONDITION(
  72. g_aws_openssl_hmac_ctx_table->init_fn != s_hmac_ctx_init_noop &&
  73. g_aws_openssl_hmac_ctx_table->clean_up_fn != s_hmac_ctx_clean_up_noop &&
  74. "libcrypto 1.0 reset called on libcrypto 1.1 vtable");
  75. g_aws_openssl_hmac_ctx_table->clean_up_fn(ctx);
  76. g_aws_openssl_hmac_ctx_table->init_fn(ctx);
  77. return 1;
  78. }
  79. #endif /* !OPENSSL_IS_AWSLC */
  80. enum aws_libcrypto_version {
  81. AWS_LIBCRYPTO_NONE = 0,
  82. AWS_LIBCRYPTO_1_0_2,
  83. AWS_LIBCRYPTO_1_1_1,
  84. AWS_LIBCRYPTO_LC,
  85. } s_libcrypto_version = AWS_LIBCRYPTO_NONE;
  86. bool s_resolve_hmac_102(void *module) {
  87. #if !defined(OPENSSL_IS_AWSLC)
  88. hmac_ctx_init init_fn = (hmac_ctx_init)HMAC_CTX_init;
  89. hmac_ctx_clean_up clean_up_fn = (hmac_ctx_clean_up)HMAC_CTX_cleanup;
  90. hmac_ctx_update update_fn = (hmac_ctx_update)HMAC_Update;
  91. hmac_ctx_final final_fn = (hmac_ctx_final)HMAC_Final;
  92. hmac_ctx_init_ex init_ex_fn = (hmac_ctx_init_ex)HMAC_Init_ex;
  93. /* were symbols bound by static linking? */
  94. bool has_102_symbols = init_fn && clean_up_fn && update_fn && final_fn && init_ex_fn;
  95. if (has_102_symbols) {
  96. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found static libcrypto 1.0.2 HMAC symbols");
  97. } else {
  98. /* If symbols aren't already found, try to find the requested version */
  99. *(void **)(&init_fn) = dlsym(module, "HMAC_CTX_init");
  100. *(void **)(&clean_up_fn) = dlsym(module, "HMAC_CTX_cleanup");
  101. *(void **)(&update_fn) = dlsym(module, "HMAC_Update");
  102. *(void **)(&final_fn) = dlsym(module, "HMAC_Final");
  103. *(void **)(&init_ex_fn) = dlsym(module, "HMAC_Init_ex");
  104. if (init_fn) {
  105. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found dynamic libcrypto 1.0.2 HMAC symbols");
  106. }
  107. }
  108. if (init_fn) {
  109. hmac_ctx_table.new_fn = (hmac_ctx_new)s_hmac_ctx_new;
  110. hmac_ctx_table.reset_fn = (hmac_ctx_reset)s_hmac_ctx_reset;
  111. hmac_ctx_table.free_fn = s_hmac_ctx_free;
  112. hmac_ctx_table.init_fn = init_fn;
  113. hmac_ctx_table.clean_up_fn = clean_up_fn;
  114. hmac_ctx_table.update_fn = update_fn;
  115. hmac_ctx_table.final_fn = final_fn;
  116. hmac_ctx_table.init_ex_fn = init_ex_fn;
  117. g_aws_openssl_hmac_ctx_table = &hmac_ctx_table;
  118. return true;
  119. }
  120. #endif
  121. return false;
  122. }
  123. bool s_resolve_hmac_111(void *module) {
  124. #if !defined(OPENSSL_IS_AWSLC)
  125. hmac_ctx_new new_fn = (hmac_ctx_new)HMAC_CTX_new;
  126. hmac_ctx_free free_fn = (hmac_ctx_free)HMAC_CTX_free;
  127. hmac_ctx_reset reset_fn = (hmac_ctx_reset)HMAC_CTX_reset;
  128. hmac_ctx_update update_fn = (hmac_ctx_update)HMAC_Update;
  129. hmac_ctx_final final_fn = (hmac_ctx_final)HMAC_Final;
  130. hmac_ctx_init_ex init_ex_fn = (hmac_ctx_init_ex)HMAC_Init_ex;
  131. /* were symbols bound by static linking? */
  132. bool has_111_symbols = new_fn && free_fn && update_fn && final_fn && init_ex_fn && reset_fn;
  133. if (has_111_symbols) {
  134. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found static libcrypto 1.1.1 HMAC symbols");
  135. } else {
  136. *(void **)(&new_fn) = dlsym(module, "HMAC_CTX_new");
  137. *(void **)(&reset_fn) = dlsym(module, "HMAC_CTX_reset");
  138. *(void **)(&free_fn) = dlsym(module, "HMAC_CTX_free");
  139. *(void **)(&update_fn) = dlsym(module, "HMAC_Update");
  140. *(void **)(&final_fn) = dlsym(module, "HMAC_Final");
  141. *(void **)(&init_ex_fn) = dlsym(module, "HMAC_Init_ex");
  142. if (new_fn) {
  143. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found dynamic libcrypto 1.1.1 HMAC symbols");
  144. }
  145. }
  146. if (new_fn) {
  147. hmac_ctx_table.new_fn = new_fn;
  148. hmac_ctx_table.reset_fn = reset_fn;
  149. hmac_ctx_table.free_fn = free_fn;
  150. hmac_ctx_table.init_fn = s_hmac_ctx_init_noop;
  151. hmac_ctx_table.clean_up_fn = s_hmac_ctx_clean_up_noop;
  152. hmac_ctx_table.update_fn = update_fn;
  153. hmac_ctx_table.final_fn = final_fn;
  154. hmac_ctx_table.init_ex_fn = init_ex_fn;
  155. g_aws_openssl_hmac_ctx_table = &hmac_ctx_table;
  156. return true;
  157. }
  158. #endif
  159. return false;
  160. }
  161. bool s_resolve_hmac_lc(void *module) {
  162. #if defined(OPENSSL_IS_AWSLC)
  163. hmac_ctx_init init_fn = (hmac_ctx_init)HMAC_CTX_init;
  164. hmac_ctx_clean_up clean_up_fn = (hmac_ctx_clean_up)HMAC_CTX_cleanup;
  165. hmac_ctx_new new_fn = (hmac_ctx_new)HMAC_CTX_new;
  166. hmac_ctx_free free_fn = (hmac_ctx_free)HMAC_CTX_free;
  167. hmac_ctx_reset reset_fn = (hmac_ctx_reset)HMAC_CTX_reset;
  168. hmac_ctx_update update_fn = (hmac_ctx_update)HMAC_Update;
  169. hmac_ctx_final final_fn = (hmac_ctx_final)HMAC_Final;
  170. hmac_ctx_init_ex init_ex_fn = (hmac_ctx_init_ex)HMAC_Init_ex;
  171. /* were symbols bound by static linking? */
  172. bool has_awslc_symbols = new_fn && free_fn && update_fn && final_fn && init_fn && init_ex_fn && reset_fn;
  173. /* If symbols aren't already found, try to find the requested version */
  174. /* when built as a shared lib, and multiple versions of libcrypto are possibly
  175. * available (e.g. brazil), select AWS-LC by default for consistency */
  176. if (has_awslc_symbols) {
  177. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found static aws-lc HMAC symbols");
  178. } else {
  179. *(void **)(&new_fn) = dlsym(module, "HMAC_CTX_new");
  180. *(void **)(&reset_fn) = dlsym(module, "HMAC_CTX_reset");
  181. *(void **)(&free_fn) = dlsym(module, "HMAC_CTX_free");
  182. *(void **)(&update_fn) = dlsym(module, "HMAC_Update");
  183. *(void **)(&final_fn) = dlsym(module, "HMAC_Final");
  184. *(void **)(&init_ex_fn) = dlsym(module, "HMAC_Init_ex");
  185. if (new_fn) {
  186. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found dynamic aws-lc HMAC symbols");
  187. }
  188. }
  189. if (new_fn) {
  190. /* Fill out the vtable for the requested version */
  191. hmac_ctx_table.new_fn = new_fn;
  192. hmac_ctx_table.reset_fn = reset_fn;
  193. hmac_ctx_table.free_fn = free_fn;
  194. hmac_ctx_table.init_fn = init_fn;
  195. hmac_ctx_table.clean_up_fn = clean_up_fn;
  196. hmac_ctx_table.update_fn = update_fn;
  197. hmac_ctx_table.final_fn = final_fn;
  198. hmac_ctx_table.init_ex_fn = init_ex_fn;
  199. g_aws_openssl_hmac_ctx_table = &hmac_ctx_table;
  200. return true;
  201. }
  202. #endif
  203. return false;
  204. }
  205. static enum aws_libcrypto_version s_resolve_libcrypto_hmac(enum aws_libcrypto_version version, void *module) {
  206. switch (version) {
  207. case AWS_LIBCRYPTO_LC:
  208. return s_resolve_hmac_lc(module) ? version : AWS_LIBCRYPTO_NONE;
  209. case AWS_LIBCRYPTO_1_1_1:
  210. return s_resolve_hmac_111(module) ? version : AWS_LIBCRYPTO_NONE;
  211. case AWS_LIBCRYPTO_1_0_2:
  212. return s_resolve_hmac_102(module) ? version : AWS_LIBCRYPTO_NONE;
  213. case AWS_LIBCRYPTO_NONE:
  214. AWS_FATAL_ASSERT(!"Attempted to resolve invalid libcrypto HMAC API version AWS_LIBCRYPTO_NONE");
  215. }
  216. return AWS_LIBCRYPTO_NONE;
  217. }
  218. #if !defined(OPENSSL_IS_AWSLC)
  219. /* EVP_MD_CTX API */
  220. /* 1.0.2 NOTE: these are macros in 1.1.x, so we have to undef them to weak link */
  221. # if defined(EVP_MD_CTX_create)
  222. # pragma push_macro("EVP_MD_CTX_create")
  223. # undef EVP_MD_CTX_create
  224. # endif
  225. extern EVP_MD_CTX *EVP_MD_CTX_create(void) __attribute__((weak, used));
  226. static evp_md_ctx_new s_EVP_MD_CTX_create = EVP_MD_CTX_create;
  227. # if defined(EVP_MD_CTX_create)
  228. # pragma pop_macro("EVP_MD_CTX_create")
  229. # endif
  230. # if defined(EVP_MD_CTX_destroy)
  231. # pragma push_macro("EVP_MD_CTX_destroy")
  232. # undef EVP_MD_CTX_destroy
  233. # endif
  234. extern void EVP_MD_CTX_destroy(EVP_MD_CTX *) __attribute__((weak, used));
  235. static evp_md_ctx_free s_EVP_MD_CTX_destroy = EVP_MD_CTX_destroy;
  236. # if defined(EVP_MD_CTX_destroy)
  237. # pragma pop_macro("EVP_MD_CTX_destroy")
  238. # endif
  239. #endif /* !OPENSSL_IS_AWSLC */
  240. extern EVP_MD_CTX *EVP_MD_CTX_new(void) __attribute__((weak, used));
  241. extern void EVP_MD_CTX_free(EVP_MD_CTX *) __attribute__((weak, used));
  242. extern int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *) __attribute__((weak, used));
  243. extern int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t) __attribute__((weak, used));
  244. extern int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *) __attribute__((weak, used));
  245. bool s_resolve_md_102(void *module) {
  246. #if !defined(OPENSSL_IS_AWSLC)
  247. evp_md_ctx_new md_create_fn = s_EVP_MD_CTX_create;
  248. evp_md_ctx_free md_destroy_fn = s_EVP_MD_CTX_destroy;
  249. evp_md_ctx_digest_init_ex md_init_ex_fn = EVP_DigestInit_ex;
  250. evp_md_ctx_digest_update md_update_fn = EVP_DigestUpdate;
  251. evp_md_ctx_digest_final_ex md_final_ex_fn = EVP_DigestFinal_ex;
  252. bool has_102_symbols = md_create_fn && md_destroy_fn && md_init_ex_fn && md_update_fn && md_final_ex_fn;
  253. if (has_102_symbols) {
  254. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found static libcrypto 1.0.2 EVP_MD symbols");
  255. } else {
  256. *(void **)(&md_create_fn) = dlsym(module, "EVP_MD_CTX_create");
  257. *(void **)(&md_destroy_fn) = dlsym(module, "EVP_MD_CTX_destroy");
  258. *(void **)(&md_init_ex_fn) = dlsym(module, "EVP_DigestInit_ex");
  259. *(void **)(&md_update_fn) = dlsym(module, "EVP_DigestUpdate");
  260. *(void **)(&md_final_ex_fn) = dlsym(module, "EVP_DigestFinal_ex");
  261. if (md_create_fn) {
  262. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found dynamic libcrypto 1.0.2 EVP_MD symbols");
  263. }
  264. }
  265. if (md_create_fn) {
  266. evp_md_ctx_table.new_fn = md_create_fn;
  267. evp_md_ctx_table.free_fn = md_destroy_fn;
  268. evp_md_ctx_table.init_ex_fn = md_init_ex_fn;
  269. evp_md_ctx_table.update_fn = md_update_fn;
  270. evp_md_ctx_table.final_ex_fn = md_final_ex_fn;
  271. g_aws_openssl_evp_md_ctx_table = &evp_md_ctx_table;
  272. return true;
  273. }
  274. #endif
  275. return false;
  276. }
  277. bool s_resolve_md_111(void *module) {
  278. #if !defined(OPENSSL_IS_AWSLC)
  279. evp_md_ctx_new md_new_fn = EVP_MD_CTX_new;
  280. evp_md_ctx_free md_free_fn = EVP_MD_CTX_free;
  281. evp_md_ctx_digest_init_ex md_init_ex_fn = EVP_DigestInit_ex;
  282. evp_md_ctx_digest_update md_update_fn = EVP_DigestUpdate;
  283. evp_md_ctx_digest_final_ex md_final_ex_fn = EVP_DigestFinal_ex;
  284. bool has_111_symbols = md_new_fn && md_free_fn && md_init_ex_fn && md_update_fn && md_final_ex_fn;
  285. if (has_111_symbols) {
  286. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found static libcrypto 1.1.1 EVP_MD symbols");
  287. } else {
  288. *(void **)(&md_new_fn) = dlsym(module, "EVP_MD_CTX_new");
  289. *(void **)(&md_free_fn) = dlsym(module, "EVP_MD_CTX_free");
  290. *(void **)(&md_init_ex_fn) = dlsym(module, "EVP_DigestInit_ex");
  291. *(void **)(&md_update_fn) = dlsym(module, "EVP_DigestUpdate");
  292. *(void **)(&md_final_ex_fn) = dlsym(module, "EVP_DigestFinal_ex");
  293. if (md_new_fn) {
  294. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found dynamic libcrypto 1.1.1 EVP_MD symbols");
  295. }
  296. }
  297. if (md_new_fn) {
  298. evp_md_ctx_table.new_fn = md_new_fn;
  299. evp_md_ctx_table.free_fn = md_free_fn;
  300. evp_md_ctx_table.init_ex_fn = md_init_ex_fn;
  301. evp_md_ctx_table.update_fn = md_update_fn;
  302. evp_md_ctx_table.final_ex_fn = md_final_ex_fn;
  303. g_aws_openssl_evp_md_ctx_table = &evp_md_ctx_table;
  304. return true;
  305. }
  306. #endif
  307. return false;
  308. }
  309. bool s_resolve_md_lc(void *module) {
  310. #if defined(OPENSSL_IS_AWSLC)
  311. evp_md_ctx_new md_new_fn = EVP_MD_CTX_new;
  312. evp_md_ctx_new md_create_fn = EVP_MD_CTX_new;
  313. evp_md_ctx_free md_free_fn = EVP_MD_CTX_free;
  314. evp_md_ctx_free md_destroy_fn = EVP_MD_CTX_destroy;
  315. evp_md_ctx_digest_init_ex md_init_ex_fn = EVP_DigestInit_ex;
  316. evp_md_ctx_digest_update md_update_fn = EVP_DigestUpdate;
  317. evp_md_ctx_digest_final_ex md_final_ex_fn = EVP_DigestFinal_ex;
  318. bool has_awslc_symbols =
  319. md_new_fn && md_create_fn && md_free_fn && md_destroy_fn && md_init_ex_fn && md_update_fn && md_final_ex_fn;
  320. if (has_awslc_symbols) {
  321. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found static aws-lc libcrypto 1.1.1 EVP_MD symbols");
  322. } else {
  323. *(void **)(&md_new_fn) = dlsym(module, "EVP_MD_CTX_new");
  324. *(void **)(&md_free_fn) = dlsym(module, "EVP_MD_CTX_free");
  325. *(void **)(&md_init_ex_fn) = dlsym(module, "EVP_DigestInit_ex");
  326. *(void **)(&md_update_fn) = dlsym(module, "EVP_DigestUpdate");
  327. *(void **)(&md_final_ex_fn) = dlsym(module, "EVP_DigestFinal_ex");
  328. if (md_new_fn) {
  329. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "found dynamic aws-lc libcrypto 1.1.1 EVP_MD symbols");
  330. }
  331. }
  332. if (md_new_fn) {
  333. /* Add the found symbols to the vtable */
  334. evp_md_ctx_table.new_fn = md_new_fn;
  335. evp_md_ctx_table.free_fn = md_free_fn;
  336. evp_md_ctx_table.init_ex_fn = md_init_ex_fn;
  337. evp_md_ctx_table.update_fn = md_update_fn;
  338. evp_md_ctx_table.final_ex_fn = md_final_ex_fn;
  339. g_aws_openssl_evp_md_ctx_table = &evp_md_ctx_table;
  340. return true;
  341. }
  342. #endif
  343. return false;
  344. }
  345. static enum aws_libcrypto_version s_resolve_libcrypto_md(enum aws_libcrypto_version version, void *module) {
  346. switch (version) {
  347. case AWS_LIBCRYPTO_LC:
  348. return s_resolve_md_lc(module) ? version : AWS_LIBCRYPTO_NONE;
  349. case AWS_LIBCRYPTO_1_1_1:
  350. return s_resolve_md_111(module) ? version : AWS_LIBCRYPTO_NONE;
  351. case AWS_LIBCRYPTO_1_0_2:
  352. return s_resolve_md_102(module) ? version : AWS_LIBCRYPTO_NONE;
  353. case AWS_LIBCRYPTO_NONE:
  354. AWS_FATAL_ASSERT(!"Attempted to resolve invalid libcrypto MD API version AWS_LIBCRYPTO_NONE");
  355. }
  356. return AWS_LIBCRYPTO_NONE;
  357. }
  358. static enum aws_libcrypto_version s_resolve_libcrypto_symbols(enum aws_libcrypto_version version, void *module) {
  359. enum aws_libcrypto_version found_version = s_resolve_libcrypto_hmac(version, module);
  360. if (found_version == AWS_LIBCRYPTO_NONE) {
  361. return AWS_LIBCRYPTO_NONE;
  362. }
  363. found_version = s_resolve_libcrypto_md(found_version, module);
  364. if (found_version == AWS_LIBCRYPTO_NONE) {
  365. return AWS_LIBCRYPTO_NONE;
  366. }
  367. return found_version;
  368. }
  369. static enum aws_libcrypto_version s_resolve_libcrypto_lib(void) {
  370. const char *libcrypto_102 = "libcrypto.so.1.0.0";
  371. const char *libcrypto_111 = "libcrypto.so.1.1";
  372. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "loading libcrypto 1.0.2");
  373. void *module = dlopen(libcrypto_102, RTLD_NOW);
  374. if (module) {
  375. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "resolving against libcrypto 1.0.2");
  376. enum aws_libcrypto_version result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_1_0_2, module);
  377. if (result == AWS_LIBCRYPTO_1_0_2) {
  378. return result;
  379. }
  380. dlclose(module);
  381. } else {
  382. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "libcrypto 1.0.2 not found");
  383. }
  384. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "loading libcrypto 1.1.1");
  385. module = dlopen(libcrypto_111, RTLD_NOW);
  386. if (module) {
  387. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "resolving against libcrypto 1.1.1");
  388. enum aws_libcrypto_version result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_1_1_1, module);
  389. if (result == AWS_LIBCRYPTO_1_1_1) {
  390. return result;
  391. }
  392. dlclose(module);
  393. } else {
  394. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "libcrypto 1.1.1 not found");
  395. }
  396. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "loading libcrypto.so");
  397. module = dlopen("libcrypto.so", RTLD_NOW);
  398. if (module) {
  399. unsigned long (*openssl_version_num)(void) = NULL;
  400. *(void **)(&openssl_version_num) = dlsym(module, "OpenSSL_version_num");
  401. if (openssl_version_num) {
  402. unsigned long version = openssl_version_num();
  403. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "libcrypto.so reported version is 0x%lx", version);
  404. enum aws_libcrypto_version result = AWS_LIBCRYPTO_NONE;
  405. if (version >= 0x10101000L) {
  406. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "probing libcrypto.so for aws-lc symbols");
  407. result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_LC, module);
  408. if (result == AWS_LIBCRYPTO_NONE) {
  409. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "probing libcrypto.so for 1.1.1 symbols");
  410. result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_1_1_1, module);
  411. }
  412. } else if (version >= 0x10002000L) {
  413. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "probing libcrypto.so for 1.0.2 symbols");
  414. result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_1_0_2, module);
  415. } else {
  416. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "libcrypto.so reported version is unsupported");
  417. }
  418. if (result != AWS_LIBCRYPTO_NONE) {
  419. return result;
  420. }
  421. } else {
  422. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "Unable to determine version of libcrypto.so");
  423. }
  424. dlclose(module);
  425. } else {
  426. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "libcrypto.so not found");
  427. }
  428. return AWS_LIBCRYPTO_NONE;
  429. }
  430. static void *s_libcrypto_module = NULL;
  431. static enum aws_libcrypto_version s_resolve_libcrypto(void) {
  432. if (s_libcrypto_version != AWS_LIBCRYPTO_NONE) {
  433. return s_libcrypto_version;
  434. }
  435. /* Try to auto-resolve against what's linked in/process space */
  436. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "searching process and loaded modules");
  437. void *process = dlopen(NULL, RTLD_NOW);
  438. #if 0
  439. // dlopen is not supported in musl. It's ok to pass NULL to s_resolve_libcrypto_symbols,
  440. // as dlsym handles it well according to man.
  441. AWS_FATAL_ASSERT(process && "Unable to load symbols from process space");
  442. #endif
  443. enum aws_libcrypto_version result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_LC, process);
  444. if (result == AWS_LIBCRYPTO_NONE) {
  445. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "did not find aws-lc symbols linked");
  446. result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_1_0_2, process);
  447. }
  448. if (result == AWS_LIBCRYPTO_NONE) {
  449. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "did not find libcrypto 1.0.2 symbols linked");
  450. result = s_resolve_libcrypto_symbols(AWS_LIBCRYPTO_1_1_1, process);
  451. }
  452. dlclose(process);
  453. if (result == AWS_LIBCRYPTO_NONE) {
  454. AWS_LOGF_DEBUG(AWS_LS_CAL_LIBCRYPTO_RESOLVE, "did not find libcrypto 1.1.1 symbols linked");
  455. AWS_LOGF_DEBUG(
  456. AWS_LS_CAL_LIBCRYPTO_RESOLVE,
  457. "libcrypto symbols were not statically linked, searching for shared libraries");
  458. result = s_resolve_libcrypto_lib();
  459. }
  460. return result;
  461. }
  462. /* Ignore warnings about how CRYPTO_get_locking_callback() always returns NULL on 1.1.1 */
  463. #if !defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ * 10 > 410)
  464. # pragma GCC diagnostic push
  465. # pragma GCC diagnostic ignored "-Waddress"
  466. #endif
  467. /* Openssl 1.0.x requires special handling for its locking callbacks or else it's not thread safe */
  468. #if !defined(OPENSSL_IS_AWSLC)
  469. static struct aws_mutex *s_libcrypto_locks = NULL;
  470. static void s_locking_fn(int mode, int n, const char *unused0, int unused1) {
  471. (void)unused0;
  472. (void)unused1;
  473. if (mode & CRYPTO_LOCK) {
  474. aws_mutex_lock(&s_libcrypto_locks[n]);
  475. } else {
  476. aws_mutex_unlock(&s_libcrypto_locks[n]);
  477. }
  478. }
  479. static unsigned long s_id_fn(void) {
  480. return (unsigned long)aws_thread_current_thread_id();
  481. }
  482. #endif
  483. void aws_cal_platform_init(struct aws_allocator *allocator) {
  484. int version = s_resolve_libcrypto();
  485. AWS_FATAL_ASSERT(version != AWS_LIBCRYPTO_NONE && "libcrypto could not be resolved");
  486. AWS_FATAL_ASSERT(g_aws_openssl_evp_md_ctx_table);
  487. AWS_FATAL_ASSERT(g_aws_openssl_hmac_ctx_table);
  488. s_libcrypto_allocator = allocator;
  489. #if !defined(OPENSSL_IS_AWSLC)
  490. /* Ensure that libcrypto 1.0.2 has working locking mechanisms. This code is macro'ed
  491. * by libcrypto to be a no-op on 1.1.1 */
  492. if (!CRYPTO_get_locking_callback()) {
  493. /* on 1.1.1 this is a no-op */
  494. CRYPTO_set_locking_callback(s_locking_fn);
  495. if (CRYPTO_get_locking_callback() == s_locking_fn) {
  496. s_libcrypto_locks = aws_mem_acquire(allocator, sizeof(struct aws_mutex) * CRYPTO_num_locks());
  497. AWS_FATAL_ASSERT(s_libcrypto_locks);
  498. size_t lock_count = (size_t)CRYPTO_num_locks();
  499. for (size_t i = 0; i < lock_count; ++i) {
  500. aws_mutex_init(&s_libcrypto_locks[i]);
  501. }
  502. }
  503. }
  504. if (!CRYPTO_get_id_callback()) {
  505. CRYPTO_set_id_callback(s_id_fn);
  506. }
  507. #endif
  508. }
  509. void aws_cal_platform_clean_up(void) {
  510. #if !defined(OPENSSL_IS_AWSLC)
  511. if (CRYPTO_get_locking_callback() == s_locking_fn) {
  512. CRYPTO_set_locking_callback(NULL);
  513. size_t lock_count = (size_t)CRYPTO_num_locks();
  514. for (size_t i = 0; i < lock_count; ++i) {
  515. aws_mutex_clean_up(&s_libcrypto_locks[i]);
  516. }
  517. aws_mem_release(s_libcrypto_allocator, s_libcrypto_locks);
  518. }
  519. if (CRYPTO_get_id_callback() == s_id_fn) {
  520. CRYPTO_set_id_callback(NULL);
  521. }
  522. #endif
  523. if (s_libcrypto_module) {
  524. dlclose(s_libcrypto_module);
  525. }
  526. s_libcrypto_allocator = NULL;
  527. }
  528. #if !defined(__GNUC__) || (__GNUC__ >= 4 && __GNUC_MINOR__ > 1)
  529. # pragma GCC diagnostic pop
  530. #endif