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