credentials.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/auth/credentials.h>
  6. #include <aws/auth/private/sso_token_utils.h>
  7. #include <aws/cal/ecc.h>
  8. #include <aws/common/environment.h>
  9. #include <aws/common/string.h>
  10. /* aws ecc identity which contains the data needed to sign a Sigv4a AWS request */
  11. struct aws_ecc_identity {
  12. struct aws_string *access_key_id;
  13. struct aws_string *session_token;
  14. struct aws_ecc_key_pair *ecc_key;
  15. };
  16. /* aws credentials identity which contains the data needed to sign an authenticated AWS request */
  17. struct aws_credentials_identity {
  18. struct aws_string *access_key_id;
  19. struct aws_string *secret_access_key;
  20. struct aws_string *session_token;
  21. };
  22. /* aws_token identity contains only a token to represent token only identities like a bearer token. */
  23. struct aws_token_identity {
  24. struct aws_string *token;
  25. };
  26. enum aws_identity_type {
  27. AWS_CREDENTIALS_IDENTITY,
  28. TOKEN_IDENTITY,
  29. ANONYMOUS_IDENTITY,
  30. ECC_IDENTITY,
  31. };
  32. /*
  33. * A structure that wraps the different types of credentials that the customer can provider to establish their
  34. * identity.
  35. */
  36. struct aws_credentials {
  37. struct aws_allocator *allocator;
  38. struct aws_atomic_var ref_count;
  39. /*
  40. * A timepoint, in seconds since epoch, at which the credentials should no longer be used because they
  41. * will have expired.
  42. *
  43. *
  44. * The primary purpose of this value is to allow providers to communicate to the caching provider any
  45. * additional constraints on how the sourced credentials should be used (STS). After refreshing the cached
  46. * credentials, the caching provider uses the following calculation to determine the next requery time:
  47. *
  48. * next_requery_time = now + cached_expiration_config;
  49. * if (cached_creds->expiration_timepoint_seconds < next_requery_time) {
  50. * next_requery_time = cached_creds->expiration_timepoint_seconds;
  51. *
  52. * The cached provider may, at its discretion, use a smaller requery time to avoid edge-case scenarios where
  53. * credential expiration becomes a race condition.
  54. *
  55. * The following leaf providers always set this value to UINT64_MAX (indefinite):
  56. * static
  57. * environment
  58. * imds
  59. * profile_config*
  60. *
  61. * * - profile_config may invoke sts which will use a non-max value
  62. *
  63. * The following leaf providers set this value to a sensible timepoint:
  64. * sts - value is based on current time + options->duration_seconds
  65. *
  66. */
  67. uint64_t expiration_timepoint_seconds;
  68. enum aws_identity_type identity_type;
  69. union {
  70. struct aws_credentials_identity credentials_identity;
  71. struct aws_token_identity token_identity;
  72. struct aws_ecc_identity ecc_identity;
  73. } identity;
  74. };
  75. /*
  76. * Credentials API implementations
  77. */
  78. struct aws_credentials *aws_credentials_new(
  79. struct aws_allocator *allocator,
  80. struct aws_byte_cursor access_key_id_cursor,
  81. struct aws_byte_cursor secret_access_key_cursor,
  82. struct aws_byte_cursor session_token_cursor,
  83. uint64_t expiration_timepoint_seconds) {
  84. if (access_key_id_cursor.ptr == NULL || access_key_id_cursor.len == 0) {
  85. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  86. return NULL;
  87. }
  88. if (secret_access_key_cursor.ptr == NULL || secret_access_key_cursor.len == 0) {
  89. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  90. return NULL;
  91. }
  92. struct aws_credentials *credentials = aws_mem_acquire(allocator, sizeof(struct aws_credentials));
  93. if (credentials == NULL) {
  94. return NULL;
  95. }
  96. AWS_ZERO_STRUCT(*credentials);
  97. credentials->allocator = allocator;
  98. aws_atomic_init_int(&credentials->ref_count, 1);
  99. credentials->identity_type = AWS_CREDENTIALS_IDENTITY;
  100. struct aws_credentials_identity *credentials_identity = &credentials->identity.credentials_identity;
  101. credentials_identity->access_key_id =
  102. aws_string_new_from_array(allocator, access_key_id_cursor.ptr, access_key_id_cursor.len);
  103. if (credentials_identity->access_key_id == NULL) {
  104. goto error;
  105. }
  106. credentials_identity->secret_access_key =
  107. aws_string_new_from_array(allocator, secret_access_key_cursor.ptr, secret_access_key_cursor.len);
  108. if (credentials_identity->secret_access_key == NULL) {
  109. goto error;
  110. }
  111. if (session_token_cursor.ptr != NULL && session_token_cursor.len > 0) {
  112. credentials_identity->session_token =
  113. aws_string_new_from_array(allocator, session_token_cursor.ptr, session_token_cursor.len);
  114. if (credentials_identity->session_token == NULL) {
  115. goto error;
  116. }
  117. }
  118. credentials->expiration_timepoint_seconds = expiration_timepoint_seconds;
  119. return credentials;
  120. error:
  121. aws_credentials_release(credentials);
  122. return NULL;
  123. }
  124. struct aws_credentials *aws_credentials_new_anonymous(struct aws_allocator *allocator) {
  125. struct aws_credentials *credentials = aws_mem_calloc(allocator, 1, sizeof(struct aws_credentials));
  126. credentials->allocator = allocator;
  127. credentials->identity_type = ANONYMOUS_IDENTITY;
  128. aws_atomic_init_int(&credentials->ref_count, 1);
  129. credentials->expiration_timepoint_seconds = UINT64_MAX;
  130. return credentials;
  131. }
  132. static void s_aws_credentials_destroy(struct aws_credentials *credentials) {
  133. if (credentials == NULL) {
  134. return;
  135. }
  136. switch (credentials->identity_type) {
  137. case AWS_CREDENTIALS_IDENTITY:
  138. aws_string_destroy(credentials->identity.credentials_identity.access_key_id);
  139. aws_string_destroy_secure(credentials->identity.credentials_identity.secret_access_key);
  140. aws_string_destroy_secure(credentials->identity.credentials_identity.session_token);
  141. break;
  142. case ECC_IDENTITY:
  143. aws_string_destroy(credentials->identity.ecc_identity.access_key_id);
  144. aws_string_destroy_secure(credentials->identity.ecc_identity.session_token);
  145. aws_ecc_key_pair_release(credentials->identity.ecc_identity.ecc_key);
  146. break;
  147. case TOKEN_IDENTITY:
  148. aws_string_destroy_secure(credentials->identity.token_identity.token);
  149. break;
  150. case ANONYMOUS_IDENTITY:
  151. break;
  152. }
  153. aws_mem_release(credentials->allocator, credentials);
  154. }
  155. void aws_credentials_acquire(const struct aws_credentials *credentials) {
  156. if (credentials == NULL) {
  157. return;
  158. }
  159. aws_atomic_fetch_add((struct aws_atomic_var *)&credentials->ref_count, 1);
  160. }
  161. void aws_credentials_release(const struct aws_credentials *credentials) {
  162. if (credentials == NULL) {
  163. return;
  164. }
  165. size_t old_value = aws_atomic_fetch_sub((struct aws_atomic_var *)&credentials->ref_count, 1);
  166. if (old_value == 1) {
  167. s_aws_credentials_destroy((struct aws_credentials *)credentials);
  168. }
  169. }
  170. static struct aws_byte_cursor s_empty_token_cursor = {
  171. .ptr = NULL,
  172. .len = 0,
  173. };
  174. struct aws_byte_cursor aws_credentials_get_access_key_id(const struct aws_credentials *credentials) {
  175. switch (credentials->identity_type) {
  176. case AWS_CREDENTIALS_IDENTITY:
  177. if (credentials->identity.credentials_identity.access_key_id != NULL) {
  178. return aws_byte_cursor_from_string(credentials->identity.credentials_identity.access_key_id);
  179. }
  180. break;
  181. case ECC_IDENTITY:
  182. if (credentials->identity.ecc_identity.access_key_id != NULL) {
  183. return aws_byte_cursor_from_string(credentials->identity.ecc_identity.access_key_id);
  184. }
  185. break;
  186. default:
  187. break;
  188. }
  189. return s_empty_token_cursor;
  190. }
  191. struct aws_byte_cursor aws_credentials_get_secret_access_key(const struct aws_credentials *credentials) {
  192. switch (credentials->identity_type) {
  193. case AWS_CREDENTIALS_IDENTITY:
  194. if (credentials->identity.credentials_identity.secret_access_key != NULL) {
  195. return aws_byte_cursor_from_string(credentials->identity.credentials_identity.secret_access_key);
  196. }
  197. break;
  198. default:
  199. break;
  200. }
  201. return s_empty_token_cursor;
  202. }
  203. struct aws_byte_cursor aws_credentials_get_session_token(const struct aws_credentials *credentials) {
  204. switch (credentials->identity_type) {
  205. case AWS_CREDENTIALS_IDENTITY:
  206. if (credentials->identity.credentials_identity.session_token != NULL) {
  207. return aws_byte_cursor_from_string(credentials->identity.credentials_identity.session_token);
  208. }
  209. break;
  210. case ECC_IDENTITY:
  211. if (credentials->identity.ecc_identity.session_token != NULL) {
  212. return aws_byte_cursor_from_string(credentials->identity.ecc_identity.session_token);
  213. }
  214. break;
  215. default:
  216. break;
  217. }
  218. return s_empty_token_cursor;
  219. }
  220. struct aws_byte_cursor aws_credentials_get_token(const struct aws_credentials *credentials) {
  221. switch (credentials->identity_type) {
  222. case TOKEN_IDENTITY:
  223. if (credentials->identity.token_identity.token != NULL) {
  224. return aws_byte_cursor_from_string(credentials->identity.token_identity.token);
  225. }
  226. break;
  227. default:
  228. break;
  229. }
  230. return s_empty_token_cursor;
  231. }
  232. uint64_t aws_credentials_get_expiration_timepoint_seconds(const struct aws_credentials *credentials) {
  233. return credentials->expiration_timepoint_seconds;
  234. }
  235. struct aws_ecc_key_pair *aws_credentials_get_ecc_key_pair(const struct aws_credentials *credentials) {
  236. if (credentials->identity_type == ECC_IDENTITY) {
  237. return credentials->identity.ecc_identity.ecc_key;
  238. }
  239. return NULL;
  240. }
  241. bool aws_credentials_is_anonymous(const struct aws_credentials *credentials) {
  242. AWS_PRECONDITION(credentials);
  243. return credentials->identity_type == ANONYMOUS_IDENTITY;
  244. }
  245. struct aws_credentials *aws_credentials_new_from_string(
  246. struct aws_allocator *allocator,
  247. const struct aws_string *access_key_id,
  248. const struct aws_string *secret_access_key,
  249. const struct aws_string *session_token,
  250. uint64_t expiration_timepoint_seconds) {
  251. struct aws_byte_cursor access_key_cursor = aws_byte_cursor_from_string(access_key_id);
  252. struct aws_byte_cursor secret_access_key_cursor = aws_byte_cursor_from_string(secret_access_key);
  253. struct aws_byte_cursor session_token_cursor;
  254. AWS_ZERO_STRUCT(session_token_cursor);
  255. if (session_token) {
  256. session_token_cursor = aws_byte_cursor_from_string(session_token);
  257. }
  258. return aws_credentials_new(
  259. allocator, access_key_cursor, secret_access_key_cursor, session_token_cursor, expiration_timepoint_seconds);
  260. }
  261. struct aws_credentials *aws_credentials_new_ecc(
  262. struct aws_allocator *allocator,
  263. struct aws_byte_cursor access_key_id,
  264. struct aws_ecc_key_pair *ecc_key,
  265. struct aws_byte_cursor session_token,
  266. uint64_t expiration_timepoint_in_seconds) {
  267. if (access_key_id.len == 0 || ecc_key == NULL) {
  268. AWS_LOGF_ERROR(AWS_LS_AUTH_GENERAL, "Provided credentials do not have a valid access_key_id or ecc_key");
  269. return NULL;
  270. }
  271. struct aws_credentials *credentials = aws_mem_calloc(allocator, 1, sizeof(struct aws_credentials));
  272. if (credentials == NULL) {
  273. return NULL;
  274. }
  275. credentials->allocator = allocator;
  276. credentials->expiration_timepoint_seconds = expiration_timepoint_in_seconds;
  277. aws_atomic_init_int(&credentials->ref_count, 1);
  278. aws_ecc_key_pair_acquire(ecc_key);
  279. credentials->identity_type = ECC_IDENTITY;
  280. credentials->identity.ecc_identity.ecc_key = ecc_key;
  281. credentials->identity.ecc_identity.access_key_id =
  282. aws_string_new_from_array(allocator, access_key_id.ptr, access_key_id.len);
  283. if (credentials->identity.ecc_identity.access_key_id == NULL) {
  284. goto on_error;
  285. }
  286. if (session_token.ptr != NULL && session_token.len > 0) {
  287. credentials->identity.ecc_identity.session_token =
  288. aws_string_new_from_array(allocator, session_token.ptr, session_token.len);
  289. if (credentials->identity.ecc_identity.session_token == NULL) {
  290. goto on_error;
  291. }
  292. }
  293. return credentials;
  294. on_error:
  295. s_aws_credentials_destroy(credentials);
  296. return NULL;
  297. }
  298. struct aws_credentials *aws_credentials_new_ecc_from_aws_credentials(
  299. struct aws_allocator *allocator,
  300. const struct aws_credentials *credentials) {
  301. struct aws_ecc_key_pair *ecc_key = aws_ecc_key_pair_new_ecdsa_p256_key_from_aws_credentials(allocator, credentials);
  302. if (ecc_key == NULL) {
  303. return NULL;
  304. }
  305. struct aws_credentials *ecc_credentials = aws_credentials_new_ecc(
  306. allocator,
  307. aws_credentials_get_access_key_id(credentials),
  308. ecc_key,
  309. aws_credentials_get_session_token(credentials),
  310. aws_credentials_get_expiration_timepoint_seconds(credentials));
  311. aws_ecc_key_pair_release(ecc_key);
  312. return ecc_credentials;
  313. }
  314. struct aws_credentials *aws_credentials_new_token(
  315. struct aws_allocator *allocator,
  316. struct aws_byte_cursor token,
  317. uint64_t expiration_timepoint_in_seconds) {
  318. if (token.ptr == NULL || token.len == 0) {
  319. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  320. return NULL;
  321. }
  322. struct aws_credentials *credentials = aws_mem_calloc(allocator, 1, sizeof(struct aws_credentials));
  323. credentials->allocator = allocator;
  324. aws_atomic_init_int(&credentials->ref_count, 1);
  325. credentials->identity_type = TOKEN_IDENTITY;
  326. struct aws_token_identity *token_identity = &credentials->identity.token_identity;
  327. token_identity->token = aws_string_new_from_array(allocator, token.ptr, token.len);
  328. credentials->expiration_timepoint_seconds = expiration_timepoint_in_seconds;
  329. return credentials;
  330. }
  331. /*
  332. * global credentials provider APIs
  333. */
  334. void aws_credentials_provider_destroy(struct aws_credentials_provider *provider) {
  335. if (provider != NULL) {
  336. provider->vtable->destroy(provider);
  337. }
  338. }
  339. struct aws_credentials_provider *aws_credentials_provider_release(struct aws_credentials_provider *provider) {
  340. if (provider == NULL) {
  341. return NULL;
  342. }
  343. size_t old_value = aws_atomic_fetch_sub(&provider->ref_count, 1);
  344. if (old_value == 1) {
  345. aws_credentials_provider_destroy(provider);
  346. }
  347. return NULL;
  348. }
  349. struct aws_credentials_provider *aws_credentials_provider_acquire(struct aws_credentials_provider *provider) {
  350. if (provider == NULL) {
  351. return NULL;
  352. }
  353. aws_atomic_fetch_add(&provider->ref_count, 1);
  354. return provider;
  355. }
  356. int aws_credentials_provider_get_credentials(
  357. struct aws_credentials_provider *provider,
  358. aws_on_get_credentials_callback_fn callback,
  359. void *user_data) {
  360. AWS_ASSERT(provider->vtable->get_credentials);
  361. return provider->vtable->get_credentials(provider, callback, user_data);
  362. }