xref: /aosp_15_r20/external/aws-crt-java/src/native/aws_signing.c (revision 3c7ae9de214676c52d19f01067dc1a404272dc11)
1 /**
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0.
4  */
5 
6 #include "crt.h"
7 
8 #include "aws_signing.h"
9 #include "credentials.h"
10 #include "http_request_utils.h"
11 #include "java_class_ids.h"
12 
13 #include <jni.h>
14 #include <string.h>
15 
16 #include <aws/auth/credentials.h>
17 #include <aws/auth/signable.h>
18 #include <aws/auth/signing.h>
19 #include <aws/auth/signing_result.h>
20 #include <aws/cal/ecc.h>
21 #include <aws/common/string.h>
22 #include <aws/http/request_response.h>
23 #include <aws/io/stream.h>
24 
25 /* on 32-bit platforms, casting pointers to longs throws a warning we don't need */
26 #if UINTPTR_MAX == 0xffffffff
27 #    if defined(_MSC_VER)
28 #        pragma warning(push)
29 #        pragma warning(disable : 4305) /* 'type cast': truncation from 'jlong' to 'jni_tls_ctx_options *' */
30 #    else
31 #        pragma GCC diagnostic push
32 #        pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
33 #        pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
34 #    endif
35 #endif
36 
37 struct s_aws_sign_request_callback_data {
38     JavaVM *jvm;
39     jobject java_signing_result_future;
40     jobject java_original_request;
41     jobject java_original_chunk_body;
42     jbyteArray java_previous_signature;
43     struct aws_http_headers *trailing_headers;
44     struct aws_input_stream *chunk_body_stream;
45     struct aws_http_message *native_request;
46     struct aws_signable *original_message_signable;
47     struct aws_byte_cursor previous_signature;
48 
49     struct aws_signing_config_data signing_config_data;
50 };
51 
aws_signing_config_data_clean_up(struct aws_signing_config_data * data,JNIEnv * env)52 void aws_signing_config_data_clean_up(struct aws_signing_config_data *data, JNIEnv *env) {
53 
54     aws_string_destroy(data->region);
55     aws_string_destroy(data->service);
56     aws_string_destroy(data->signed_body_value);
57 
58     if (data->java_sign_header_predicate) {
59         (*env)->DeleteGlobalRef(env, data->java_sign_header_predicate);
60     }
61     if (data->java_credentials_provider) {
62         (*env)->DeleteGlobalRef(env, data->java_credentials_provider);
63     }
64     aws_credentials_release(data->credentials);
65 }
66 
s_cleanup_callback_data(struct s_aws_sign_request_callback_data * callback_data,JNIEnv * env)67 static void s_cleanup_callback_data(struct s_aws_sign_request_callback_data *callback_data, JNIEnv *env) {
68     if (callback_data == NULL || env == NULL) {
69         return;
70     }
71 
72     if (callback_data->java_signing_result_future != NULL) {
73         (*env)->DeleteGlobalRef(env, callback_data->java_signing_result_future);
74     }
75 
76     if (callback_data->java_original_request != NULL) {
77         (*env)->DeleteGlobalRef(env, callback_data->java_original_request);
78     }
79 
80     if (callback_data->java_original_chunk_body != NULL) {
81         (*env)->DeleteGlobalRef(env, callback_data->java_original_chunk_body);
82     }
83 
84     if (callback_data->native_request) {
85         aws_http_message_release(callback_data->native_request);
86     }
87 
88     if (callback_data->original_message_signable) {
89         aws_signable_destroy(callback_data->original_message_signable);
90     }
91 
92     if (callback_data->chunk_body_stream != NULL) {
93         aws_input_stream_destroy(callback_data->chunk_body_stream);
94     }
95     if (callback_data->trailing_headers != NULL) {
96         aws_http_headers_release(callback_data->trailing_headers);
97     }
98 
99     if (callback_data->previous_signature.len > 0 && callback_data->java_previous_signature != NULL) {
100         aws_jni_byte_cursor_from_jbyteArray_release(
101             env, callback_data->java_previous_signature, callback_data->previous_signature);
102     }
103 
104     if (callback_data->java_previous_signature != NULL) {
105         (*env)->DeleteGlobalRef(env, callback_data->java_previous_signature);
106     }
107 
108     aws_signing_config_data_clean_up(&callback_data->signing_config_data, env);
109 
110     aws_mem_release(aws_jni_get_allocator(), callback_data);
111 }
112 
s_create_signed_java_http_request(JNIEnv * env,struct aws_http_message * native_request,jobject java_original_request)113 static jobject s_create_signed_java_http_request(
114     JNIEnv *env,
115     struct aws_http_message *native_request,
116     jobject java_original_request) {
117     jobject jni_body_stream =
118         (*env)->GetObjectField(env, java_original_request, http_request_properties.body_stream_field_id);
119 
120     jobject http_request = aws_java_http_request_from_native(env, native_request, jni_body_stream);
121 
122     if (jni_body_stream != NULL) {
123         (*env)->DeleteLocalRef(env, jni_body_stream);
124     }
125 
126     return http_request;
127 }
128 
s_complete_signing_exceptionally(JNIEnv * env,struct s_aws_sign_request_callback_data * callback_data,int error_code)129 static void s_complete_signing_exceptionally(
130     JNIEnv *env,
131     struct s_aws_sign_request_callback_data *callback_data,
132     int error_code) {
133 
134     if (error_code == AWS_ERROR_SUCCESS) {
135         error_code = AWS_ERROR_UNKNOWN;
136     }
137 
138     jobject crt_exception = aws_jni_new_crt_exception_from_error_code(env, error_code);
139 
140     (*env)->CallBooleanMethod(
141         env,
142         callback_data->java_signing_result_future,
143         completable_future_properties.complete_exceptionally_method_id,
144         crt_exception);
145 
146     aws_jni_check_and_clear_exception(env);
147     (*env)->DeleteLocalRef(env, crt_exception);
148 }
149 
s_aws_complete_signing_result(JNIEnv * env,struct aws_signing_result * result,struct s_aws_sign_request_callback_data * callback_data,jobject java_signed_request)150 static void s_aws_complete_signing_result(
151     JNIEnv *env,
152     struct aws_signing_result *result,
153     struct s_aws_sign_request_callback_data *callback_data,
154     jobject java_signed_request) {
155     jbyteArray java_signature = NULL;
156     jobject java_signing_result = NULL;
157 
158     struct aws_string *signature = NULL;
159     aws_signing_result_get_property(result, g_aws_signature_property_name, &signature);
160 
161     /* Anonymous requests don't have a signature because they are not signed. */
162     if (signature != NULL) {
163         struct aws_byte_cursor signature_cursor = aws_byte_cursor_from_string(signature);
164         java_signature = aws_jni_byte_array_from_cursor(env, &signature_cursor);
165     }
166 
167     java_signing_result = (*env)->NewObject(
168         env, aws_signing_result_properties.aws_signing_result_class, aws_signing_result_properties.constructor);
169     if ((*env)->ExceptionCheck(env) || java_signing_result == NULL) {
170         s_complete_signing_exceptionally(env, callback_data, AWS_ERROR_UNKNOWN);
171         goto done;
172     }
173 
174     (*env)->SetObjectField(
175         env, java_signing_result, aws_signing_result_properties.signed_request_field_id, java_signed_request);
176     (*env)->SetObjectField(env, java_signing_result, aws_signing_result_properties.signature_field_id, java_signature);
177 
178     (*env)->CallBooleanMethod(
179         env,
180         callback_data->java_signing_result_future,
181         completable_future_properties.complete_method_id,
182         java_signing_result);
183 
184     /* I have no idea what we should do here... but the JVM really doesn't like us NOT calling this function after
185        we cross the barrier. */
186     AWS_FATAL_ASSERT(!aws_jni_check_and_clear_exception(env));
187 
188 done:
189 
190     if (java_signature != NULL) {
191         (*env)->DeleteLocalRef(env, java_signature);
192     }
193 
194     if (java_signing_result != NULL) {
195         (*env)->DeleteLocalRef(env, java_signing_result);
196     }
197 
198     if (java_signed_request != NULL) {
199         (*env)->DeleteLocalRef(env, java_signed_request);
200     }
201 }
202 
s_aws_request_signing_complete(struct aws_signing_result * result,int error_code,void * userdata)203 static void s_aws_request_signing_complete(struct aws_signing_result *result, int error_code, void *userdata) {
204 
205     struct s_aws_sign_request_callback_data *callback_data = userdata;
206 
207     /********** JNI ENV ACQUIRE **********/
208     JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
209     if (env == NULL) {
210         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
211         return;
212     }
213 
214     if (result == NULL || error_code != AWS_ERROR_SUCCESS) {
215         s_complete_signing_exceptionally(env, callback_data, error_code);
216         goto done;
217     }
218 
219     if (aws_apply_signing_result_to_http_request(callback_data->native_request, aws_jni_get_allocator(), result)) {
220         s_complete_signing_exceptionally(env, callback_data, aws_last_error());
221         goto done;
222     }
223 
224     jobject java_signed_request =
225         s_create_signed_java_http_request(env, callback_data->native_request, callback_data->java_original_request);
226     if (java_signed_request == NULL) {
227         s_complete_signing_exceptionally(env, callback_data, aws_last_error());
228         goto done;
229     }
230 
231     s_aws_complete_signing_result(env, result, callback_data, java_signed_request);
232 
233 done:;
234 
235     JavaVM *jvm = callback_data->jvm;
236     s_cleanup_callback_data(callback_data, env);
237 
238     aws_jni_release_thread_env(jvm, env);
239     /********** JNI ENV RELEASE **********/
240 }
241 
s_aws_chunk_like_signing_complete(struct aws_signing_result * result,int error_code,void * userdata)242 static void s_aws_chunk_like_signing_complete(struct aws_signing_result *result, int error_code, void *userdata) {
243 
244     struct s_aws_sign_request_callback_data *callback_data = userdata;
245 
246     /********** JNI ENV ACQUIRE **********/
247     JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
248     if (env == NULL) {
249         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
250         return;
251     }
252 
253     if (result == NULL || error_code != AWS_ERROR_SUCCESS) {
254         s_complete_signing_exceptionally(env, callback_data, error_code);
255         goto done;
256     }
257 
258     s_aws_complete_signing_result(env, result, callback_data, NULL);
259 
260 done:;
261 
262     JavaVM *jvm = callback_data->jvm;
263     s_cleanup_callback_data(callback_data, env);
264 
265     aws_jni_release_thread_env(jvm, env);
266     /********** JNI ENV RELEASE **********/
267 }
268 
s_aws_chunk_signing_complete(struct aws_signing_result * result,int error_code,void * userdata)269 static void s_aws_chunk_signing_complete(struct aws_signing_result *result, int error_code, void *userdata) {
270     s_aws_chunk_like_signing_complete(result, error_code, userdata);
271 }
272 
s_aws_trailing_headers_signing_complete(struct aws_signing_result * result,int error_code,void * userdata)273 static void s_aws_trailing_headers_signing_complete(struct aws_signing_result *result, int error_code, void *userdata) {
274     s_aws_chunk_like_signing_complete(result, error_code, userdata);
275 }
276 
s_should_sign_header(const struct aws_byte_cursor * name,void * user_data)277 static bool s_should_sign_header(const struct aws_byte_cursor *name, void *user_data) {
278     struct aws_signing_config_data *callback_data = user_data;
279 
280     /********** JNI ENV ACQUIRE **********/
281     JNIEnv *env = aws_jni_acquire_thread_env(callback_data->jvm);
282     if (env == NULL) {
283         /* If we can't get an environment, then the JVM is probably shutting down.  Don't crash. */
284         return false;
285     }
286 
287     jstring header_name = aws_jni_string_from_cursor(env, name);
288 
289     bool result = (*env)->CallBooleanMethod(
290         env, callback_data->java_sign_header_predicate, predicate_properties.test_method_id, (jobject)header_name);
291     AWS_FATAL_ASSERT(!aws_jni_check_and_clear_exception(env));
292 
293     (*env)->DeleteLocalRef(env, header_name);
294 
295     aws_jni_release_thread_env(callback_data->jvm, env);
296     /********** JNI ENV RELEASE **********/
297 
298     return result;
299 }
300 
aws_build_signing_config(JNIEnv * env,jobject java_config,struct aws_signing_config_data * config_data,struct aws_signing_config_aws * config)301 int aws_build_signing_config(
302     JNIEnv *env,
303     jobject java_config,
304     struct aws_signing_config_data *config_data,
305     struct aws_signing_config_aws *config) {
306 
307     jint jvmresult = (*env)->GetJavaVM(env, &config_data->jvm);
308     AWS_FATAL_ASSERT(jvmresult == 0);
309 
310     config->config_type = AWS_SIGNING_CONFIG_AWS;
311     config->algorithm = (enum aws_signing_algorithm)(*env)->GetIntField(
312         env, java_config, aws_signing_config_properties.algorithm_field_id);
313     config->signature_type = (enum aws_signature_type)(*env)->GetIntField(
314         env, java_config, aws_signing_config_properties.signature_type_field_id);
315 
316     jstring region = (jstring)(*env)->GetObjectField(env, java_config, aws_signing_config_properties.region_field_id);
317     if (region == NULL) {
318         AWS_ZERO_STRUCT(config->region);
319     } else {
320         config_data->region = aws_jni_new_string_from_jstring(env, region);
321         config->region = aws_byte_cursor_from_string(config_data->region);
322     }
323 
324     jstring service = (jstring)(*env)->GetObjectField(env, java_config, aws_signing_config_properties.service_field_id);
325     if (service == NULL) {
326         AWS_ZERO_STRUCT(config->service);
327     } else {
328         config_data->service = aws_jni_new_string_from_jstring(env, service);
329         config->service = aws_byte_cursor_from_string(config_data->service);
330     }
331 
332     int64_t epoch_time_millis = (*env)->GetLongField(env, java_config, aws_signing_config_properties.time_field_id);
333     aws_date_time_init_epoch_millis(&config->date, (uint64_t)epoch_time_millis);
334 
335     jobject sign_header_predicate =
336         (*env)->GetObjectField(env, java_config, aws_signing_config_properties.should_sign_header_field_id);
337     if (sign_header_predicate != NULL) {
338         config_data->java_sign_header_predicate = (*env)->NewGlobalRef(env, sign_header_predicate);
339         AWS_FATAL_ASSERT(config_data->java_sign_header_predicate != NULL);
340 
341         config->should_sign_header = s_should_sign_header;
342         config->should_sign_header_ud = config_data;
343     }
344 
345     config->flags.use_double_uri_encode =
346         (*env)->GetBooleanField(env, java_config, aws_signing_config_properties.use_double_uri_encode_field_id);
347     config->flags.should_normalize_uri_path =
348         (*env)->GetBooleanField(env, java_config, aws_signing_config_properties.should_normalize_uri_path_field_id);
349     config->flags.omit_session_token =
350         (*env)->GetBooleanField(env, java_config, aws_signing_config_properties.omit_session_token_field_id);
351 
352     jstring signed_body_value =
353         (jstring)(*env)->GetObjectField(env, java_config, aws_signing_config_properties.signed_body_value_field_id);
354     if (signed_body_value == NULL) {
355         AWS_ZERO_STRUCT(config->signed_body_value);
356     } else {
357         config_data->signed_body_value = aws_jni_new_string_from_jstring(env, signed_body_value);
358         config->signed_body_value = aws_byte_cursor_from_string(config_data->signed_body_value);
359     }
360 
361     config->signed_body_header =
362         (*env)->GetIntField(env, java_config, aws_signing_config_properties.signed_body_header_field_id);
363 
364     jobject provider =
365         (*env)->GetObjectField(env, java_config, aws_signing_config_properties.credentials_provider_field_id);
366     if (provider != NULL) {
367         config->credentials_provider =
368             (void *)(*env)->CallLongMethod(env, provider, crt_resource_properties.get_native_handle_method_id);
369         /* Keep the java object alive */
370         config_data->java_credentials_provider = (*env)->NewGlobalRef(env, provider);
371         AWS_FATAL_ASSERT(config_data->java_credentials_provider != NULL);
372         aws_jni_check_and_clear_exception(env);
373     }
374 
375     jobject credentials = (*env)->GetObjectField(env, java_config, aws_signing_config_properties.credentials_field_id);
376     if (credentials != NULL) {
377         config_data->credentials = aws_credentials_new_from_java_credentials(env, credentials);
378         config->credentials = config_data->credentials;
379     }
380 
381     config->expiration_in_seconds =
382         (uint64_t)(*env)->GetLongField(env, java_config, aws_signing_config_properties.expiration_in_seconds_field_id);
383 
384     if (aws_jni_check_and_clear_exception(env)) {
385         return aws_raise_error(AWS_ERROR_HTTP_CALLBACK_FAILURE);
386     }
387 
388     return AWS_OP_SUCCESS;
389 }
390 
391 JNIEXPORT
Java_software_amazon_awssdk_crt_auth_signing_AwsSigner_awsSignerSignRequest(JNIEnv * env,jclass jni_class,jobject java_http_request,jbyteArray marshalled_request,jobject java_signing_config,jobject java_signing_result_future)392 void JNICALL Java_software_amazon_awssdk_crt_auth_signing_AwsSigner_awsSignerSignRequest(
393     JNIEnv *env,
394     jclass jni_class,
395     jobject java_http_request,
396     jbyteArray marshalled_request,
397     jobject java_signing_config,
398     jobject java_signing_result_future) {
399 
400     (void)jni_class;
401     aws_cache_jni_ids(env);
402 
403     struct aws_allocator *allocator = aws_jni_get_allocator();
404     struct s_aws_sign_request_callback_data *callback_data =
405         aws_mem_calloc(allocator, 1, sizeof(struct s_aws_sign_request_callback_data));
406     if (callback_data == NULL) {
407         aws_jni_throw_runtime_exception(env, "Failed to allocated sign request callback data");
408         return;
409     }
410 
411     jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
412     AWS_FATAL_ASSERT(jvmresult == 0);
413 
414     callback_data->java_signing_result_future = (*env)->NewGlobalRef(env, java_signing_result_future);
415     AWS_FATAL_ASSERT(callback_data->java_signing_result_future != NULL);
416 
417     callback_data->java_original_request = (*env)->NewGlobalRef(env, java_http_request);
418     AWS_FATAL_ASSERT(callback_data->java_original_request != NULL);
419 
420     /* Build a native aws_signing_config_aws object */
421     struct aws_signing_config_aws signing_config;
422     AWS_ZERO_STRUCT(signing_config);
423 
424     if (aws_build_signing_config(env, java_signing_config, &callback_data->signing_config_data, &signing_config)) {
425         aws_jni_throw_runtime_exception(env, "Failed to create signing configuration");
426         goto on_error;
427     }
428 
429     jobject java_http_request_body_stream =
430         (*env)->GetObjectField(env, java_http_request, http_request_properties.body_stream_field_id);
431 
432     callback_data->native_request =
433         aws_http_request_new_from_java_http_request(env, marshalled_request, java_http_request_body_stream);
434     if (callback_data->native_request == NULL) {
435         aws_jni_throw_runtime_exception(env, "Failed to create native http request from Java HttpRequest");
436         goto on_error;
437     }
438 
439     callback_data->original_message_signable = aws_signable_new_http_request(allocator, callback_data->native_request);
440     if (callback_data->original_message_signable == NULL) {
441         aws_jni_throw_runtime_exception(env, "Failed to create signable from http request");
442         goto on_error;
443     }
444 
445     /* Sign the native request */
446     if (aws_sign_request_aws(
447             allocator,
448             callback_data->original_message_signable,
449             (struct aws_signing_config_base *)&signing_config,
450             s_aws_request_signing_complete,
451             callback_data)) {
452         aws_jni_throw_runtime_exception(env, "Failed to initiate signing process for HttpRequest");
453         goto on_error;
454     }
455 
456     return;
457 
458 on_error:
459 
460     s_cleanup_callback_data(callback_data, env);
461 }
462 
463 JNIEXPORT
Java_software_amazon_awssdk_crt_auth_signing_AwsSigner_awsSignerSignChunk(JNIEnv * env,jclass jni_class,jobject java_chunk_body_stream,jbyteArray java_previous_signature,jobject java_signing_config,jobject java_signing_result_future)464 void JNICALL Java_software_amazon_awssdk_crt_auth_signing_AwsSigner_awsSignerSignChunk(
465     JNIEnv *env,
466     jclass jni_class,
467     jobject java_chunk_body_stream,
468     jbyteArray java_previous_signature,
469     jobject java_signing_config,
470     jobject java_signing_result_future) {
471 
472     (void)jni_class;
473     aws_cache_jni_ids(env);
474 
475     struct aws_allocator *allocator = aws_jni_get_allocator();
476     struct s_aws_sign_request_callback_data *callback_data =
477         aws_mem_calloc(allocator, 1, sizeof(struct s_aws_sign_request_callback_data));
478     if (callback_data == NULL) {
479         aws_jni_throw_runtime_exception(env, "Failed to allocate chunk signing callback data");
480         return;
481     }
482 
483     jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
484     AWS_FATAL_ASSERT(jvmresult == 0);
485 
486     callback_data->java_signing_result_future = (*env)->NewGlobalRef(env, java_signing_result_future);
487     AWS_FATAL_ASSERT(callback_data->java_signing_result_future != NULL);
488 
489     if (java_chunk_body_stream != NULL) {
490         callback_data->java_original_chunk_body = (*env)->NewGlobalRef(env, java_chunk_body_stream);
491         AWS_FATAL_ASSERT(callback_data->java_original_chunk_body != NULL);
492 
493         callback_data->chunk_body_stream = aws_input_stream_new_from_java_http_request_body_stream(
494             aws_jni_get_allocator(), env, java_chunk_body_stream);
495         if (callback_data->chunk_body_stream == NULL) {
496             aws_jni_throw_runtime_exception(env, "Error building chunk body stream");
497             goto on_error;
498         }
499     }
500 
501     /* Build a native aws_signing_config_aws object */
502     struct aws_signing_config_aws signing_config;
503     AWS_ZERO_STRUCT(signing_config);
504     if (aws_build_signing_config(env, java_signing_config, &callback_data->signing_config_data, &signing_config)) {
505         aws_jni_throw_runtime_exception(env, "Failed to create signing configuration");
506         goto on_error;
507     }
508 
509     callback_data->java_previous_signature = (*env)->NewGlobalRef(env, java_previous_signature);
510     callback_data->previous_signature = aws_jni_byte_cursor_from_jbyteArray_acquire(env, java_previous_signature);
511 
512     callback_data->original_message_signable =
513         aws_signable_new_chunk(allocator, callback_data->chunk_body_stream, callback_data->previous_signature);
514     if (callback_data->original_message_signable == NULL) {
515         aws_jni_throw_runtime_exception(env, "Failed to create signable from chunk data");
516         goto on_error;
517     }
518 
519     /* Sign the native request */
520     if (aws_sign_request_aws(
521             allocator,
522             callback_data->original_message_signable,
523             (struct aws_signing_config_base *)&signing_config,
524             s_aws_chunk_signing_complete,
525             callback_data)) {
526         aws_jni_throw_runtime_exception(env, "Failed to initiate signing process for Chunk");
527         goto on_error;
528     }
529 
530     return;
531 
532 on_error:
533 
534     s_cleanup_callback_data(callback_data, env);
535 }
536 
537 JNIEXPORT
Java_software_amazon_awssdk_crt_auth_signing_AwsSigner_awsSignerSignTrailingHeaders(JNIEnv * env,jclass jni_class,jbyteArray marshalled_headers,jbyteArray java_previous_signature,jobject java_signing_config,jobject java_signing_result_future)538 void JNICALL Java_software_amazon_awssdk_crt_auth_signing_AwsSigner_awsSignerSignTrailingHeaders(
539     JNIEnv *env,
540     jclass jni_class,
541     jbyteArray marshalled_headers,
542     jbyteArray java_previous_signature,
543     jobject java_signing_config,
544     jobject java_signing_result_future) {
545 
546     (void)jni_class;
547     aws_cache_jni_ids(env);
548 
549     struct aws_allocator *allocator = aws_jni_get_allocator();
550     struct s_aws_sign_request_callback_data *callback_data =
551         aws_mem_calloc(allocator, 1, sizeof(struct s_aws_sign_request_callback_data));
552     /* we no longer worry about allocation failures */
553 
554     jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
555     AWS_FATAL_ASSERT(jvmresult == 0);
556 
557     callback_data->java_signing_result_future = (*env)->NewGlobalRef(env, java_signing_result_future);
558     AWS_FATAL_ASSERT(callback_data->java_signing_result_future != NULL);
559 
560     callback_data->trailing_headers = aws_http_headers_new_from_java_http_headers(env, marshalled_headers);
561     if (callback_data->trailing_headers == NULL) {
562         goto on_error;
563     }
564 
565     /* Build a native aws_signing_config_aws object */
566     struct aws_signing_config_aws signing_config;
567     AWS_ZERO_STRUCT(signing_config);
568 
569     if (aws_build_signing_config(env, java_signing_config, &callback_data->signing_config_data, &signing_config)) {
570         aws_jni_throw_runtime_exception(env, "Failed to create signing configuration");
571         goto on_error;
572     }
573 
574     callback_data->java_previous_signature = (*env)->NewGlobalRef(env, java_previous_signature);
575     callback_data->previous_signature = aws_jni_byte_cursor_from_jbyteArray_acquire(env, java_previous_signature);
576 
577     callback_data->original_message_signable = aws_signable_new_trailing_headers(
578         allocator, callback_data->trailing_headers, callback_data->previous_signature);
579     if (callback_data->original_message_signable == NULL) {
580         aws_jni_throw_runtime_exception(env, "Failed to create signable from trailing headers data");
581         goto on_error;
582     }
583 
584     /* Sign the native request */
585     if (aws_sign_request_aws(
586             allocator,
587             callback_data->original_message_signable,
588             (struct aws_signing_config_base *)&signing_config,
589             s_aws_trailing_headers_signing_complete,
590             callback_data)) {
591         aws_jni_throw_runtime_exception(env, "Failed to initiate signing process for trailing headers");
592         goto on_error;
593     }
594 
595     return;
596 
597 on_error:
598 
599     s_cleanup_callback_data(callback_data, env);
600 }
601 
602 JNIEXPORT
Java_software_amazon_awssdk_crt_auth_signing_AwsSigningUtils_awsSigningUtilsVerifyEcdsaSignature(JNIEnv * env,jclass jni_class,jobject java_http_request,jbyteArray java_marshalled_request,jstring java_expected_canonical_request,jobject java_signing_config,jbyteArray java_signature,jstring java_verifier_pub_x,jstring java_verifier_pub_y)603 bool JNICALL Java_software_amazon_awssdk_crt_auth_signing_AwsSigningUtils_awsSigningUtilsVerifyEcdsaSignature(
604     JNIEnv *env,
605     jclass jni_class,
606     jobject java_http_request,
607     jbyteArray java_marshalled_request,
608     jstring java_expected_canonical_request,
609     jobject java_signing_config,
610     jbyteArray java_signature,
611     jstring java_verifier_pub_x,
612     jstring java_verifier_pub_y) {
613 
614     (void)jni_class;
615     aws_cache_jni_ids(env);
616 
617     bool success = false;
618 
619     struct aws_string *expected_canonical_request = NULL;
620     struct aws_byte_cursor signature_cursor;
621     AWS_ZERO_STRUCT(signature_cursor);
622     struct aws_string *pub_x = NULL;
623     struct aws_string *pub_y = NULL;
624 
625     struct aws_allocator *allocator = aws_jni_get_allocator();
626     struct s_aws_sign_request_callback_data *callback_data =
627         aws_mem_calloc(allocator, 1, sizeof(struct s_aws_sign_request_callback_data));
628     if (callback_data == NULL) {
629         goto done;
630     }
631 
632     if (java_signature == NULL) {
633         goto done;
634     }
635 
636     signature_cursor = aws_jni_byte_cursor_from_jbyteArray_acquire(env, java_signature);
637     if (signature_cursor.len == 0) {
638         goto done;
639     }
640 
641     jint jvmresult = (*env)->GetJavaVM(env, &callback_data->jvm);
642     AWS_FATAL_ASSERT(jvmresult == 0);
643 
644     /* Build a native aws_signing_config_aws object */
645     struct aws_signing_config_aws signing_config;
646     AWS_ZERO_STRUCT(signing_config);
647 
648     if (aws_build_signing_config(env, java_signing_config, &callback_data->signing_config_data, &signing_config)) {
649         goto done;
650     }
651 
652     jobject java_http_request_body_stream =
653         (*env)->GetObjectField(env, java_http_request, http_request_properties.body_stream_field_id);
654 
655     callback_data->native_request =
656         aws_http_request_new_from_java_http_request(env, java_marshalled_request, java_http_request_body_stream);
657     if (callback_data->native_request == NULL) {
658         goto done;
659     }
660 
661     callback_data->original_message_signable = aws_signable_new_http_request(allocator, callback_data->native_request);
662     if (callback_data->original_message_signable == NULL) {
663         goto done;
664     }
665 
666     expected_canonical_request = aws_jni_new_string_from_jstring(env, java_expected_canonical_request);
667     pub_x = aws_jni_new_string_from_jstring(env, java_verifier_pub_x);
668     pub_y = aws_jni_new_string_from_jstring(env, java_verifier_pub_y);
669 
670     if (aws_verify_sigv4a_signing(
671             allocator,
672             callback_data->original_message_signable,
673             (struct aws_signing_config_base *)&signing_config,
674             aws_byte_cursor_from_string(expected_canonical_request),
675             signature_cursor,
676             aws_byte_cursor_from_string(pub_x),
677             aws_byte_cursor_from_string(pub_y))) {
678         aws_jni_throw_runtime_exception(env, aws_error_str(aws_last_error()));
679         goto done;
680     }
681 
682     success = true;
683 
684 done:
685 
686     s_cleanup_callback_data(callback_data, env);
687 
688     aws_string_destroy(expected_canonical_request);
689     if (signature_cursor.len > 0) {
690         aws_jni_byte_cursor_from_jbyteArray_release(env, java_signature, signature_cursor);
691     }
692     aws_string_destroy(pub_x);
693     aws_string_destroy(pub_y);
694 
695     return success;
696 }
697 
698 JNIEXPORT
Java_software_amazon_awssdk_crt_auth_signing_AwsSigningUtils_awsSigningUtilsVerifyRawSha256EcdsaSignature(JNIEnv * env,jclass jni_class,jbyteArray java_string_to_sign,jbyteArray java_signature,jstring java_verifier_pub_x,jstring java_verifier_pub_y)699 bool JNICALL Java_software_amazon_awssdk_crt_auth_signing_AwsSigningUtils_awsSigningUtilsVerifyRawSha256EcdsaSignature(
700     JNIEnv *env,
701     jclass jni_class,
702     jbyteArray java_string_to_sign,
703     jbyteArray java_signature,
704     jstring java_verifier_pub_x,
705     jstring java_verifier_pub_y) {
706 
707     (void)jni_class;
708     aws_cache_jni_ids(env);
709 
710     bool success = false;
711     struct aws_allocator *allocator = aws_jni_get_allocator();
712 
713     struct aws_byte_cursor string_to_sign_cursor;
714     AWS_ZERO_STRUCT(string_to_sign_cursor);
715     struct aws_byte_cursor signature_cursor;
716     AWS_ZERO_STRUCT(signature_cursor);
717 
718     struct aws_ecc_key_pair *ecc_key = NULL;
719     struct aws_string *pub_x = NULL;
720     struct aws_string *pub_y = NULL;
721 
722     if (java_string_to_sign == NULL || java_signature == NULL || java_verifier_pub_x == NULL ||
723         java_verifier_pub_y == NULL) {
724         goto done;
725     }
726 
727     pub_x = aws_jni_new_string_from_jstring(env, java_verifier_pub_x);
728     pub_y = aws_jni_new_string_from_jstring(env, java_verifier_pub_y);
729     if (pub_x == NULL || pub_y == NULL) {
730         goto done;
731     }
732 
733     ecc_key = aws_ecc_key_new_from_hex_coordinates(
734         allocator, AWS_CAL_ECDSA_P256, aws_byte_cursor_from_string(pub_x), aws_byte_cursor_from_string(pub_y));
735     if (ecc_key == NULL) {
736         goto done;
737     }
738 
739     string_to_sign_cursor = aws_jni_byte_cursor_from_jbyteArray_acquire(env, java_string_to_sign);
740     signature_cursor = aws_jni_byte_cursor_from_jbyteArray_acquire(env, java_signature);
741 
742     if (aws_validate_v4a_authorization_value(allocator, ecc_key, string_to_sign_cursor, signature_cursor)) {
743         goto done;
744     }
745 
746     success = true;
747 
748 done:
749 
750     if (string_to_sign_cursor.len > 0) {
751         aws_jni_byte_cursor_from_jbyteArray_release(env, java_string_to_sign, string_to_sign_cursor);
752     }
753 
754     if (signature_cursor.len > 0) {
755         aws_jni_byte_cursor_from_jbyteArray_release(env, java_signature, signature_cursor);
756     }
757 
758     aws_string_destroy(pub_x);
759     aws_string_destroy(pub_y);
760 
761     aws_ecc_key_pair_release(ecc_key);
762 
763     return success;
764 }
765 
766 #if UINTPTR_MAX == 0xffffffff
767 #    if defined(_MSC_VER)
768 #        pragma warning(pop)
769 #    else
770 #        pragma GCC diagnostic pop
771 #    endif
772 #endif
773