1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5 #include "custom_key_op_handler.h"
6
7 #include "java_class_ids.h"
8 #include "tls_context_pkcs11_options.h"
9 #include <aws/common/string.h>
10 #include <aws/io/tls_channel_handler.h>
11
12 struct aws_jni_custom_key_op_handler {
13 /**
14 * The C class containing the key operations. We extend/define it's VTable to allow
15 * us to have it call into the customer's Java code.
16 */
17 struct aws_custom_key_op_handler base;
18
19 /** A pointer to the JVM for getting JNI threads */
20 JavaVM *jvm;
21
22 /**
23 * A reference to the Java class that this struct is linked to.
24 * The interface, strings, etc, can be gotten from this class.
25 */
26 jobject jni_custom_key_op;
27
28 /** The allocator to use */
29 struct aws_allocator *allocator;
30 };
31
s_aws_custom_key_op_handler_perform_operation(struct aws_custom_key_op_handler * key_op_handler,struct aws_tls_key_operation * operation)32 static void s_aws_custom_key_op_handler_perform_operation(
33 struct aws_custom_key_op_handler *key_op_handler,
34 struct aws_tls_key_operation *operation) {
35
36 struct aws_jni_custom_key_op_handler *op_handler = (struct aws_jni_custom_key_op_handler *)key_op_handler->impl;
37 AWS_FATAL_ASSERT(op_handler != NULL);
38
39 jbyteArray jni_input_data = NULL;
40 jobject jni_operation = NULL;
41 bool success = false;
42 AWS_ASSERT(operation != NULL);
43
44 /* Get the Java ENV */
45 JNIEnv *env = aws_jni_acquire_thread_env(op_handler->jvm);
46 if (env == NULL) {
47 /* JVM is likely shutting down. Do not crash but log error. */
48 AWS_LOGF_ERROR(
49 AWS_LS_COMMON_IO,
50 "java_custom_key_op_handler=%p perform operation: Could not get Java ENV!",
51 (void *)op_handler);
52 goto clean_up;
53 }
54
55 /* Create DirectByteBuffer */
56 struct aws_byte_cursor input_data = aws_tls_key_operation_get_input(operation);
57 jni_input_data = aws_jni_byte_array_from_cursor(env, &input_data);
58 if (jni_input_data == NULL) {
59 aws_jni_check_and_clear_exception(env);
60 goto clean_up;
61 }
62
63 /* Create TlsKeyOperation */
64 jni_operation = (*env)->NewObject(
65 env,
66 tls_key_operation_properties.cls,
67 tls_key_operation_properties.constructor,
68 (jlong)(intptr_t)operation,
69 jni_input_data,
70 (jint)aws_tls_key_operation_get_type(operation),
71 (jint)aws_tls_key_operation_get_signature_algorithm(operation),
72 (jint)aws_tls_key_operation_get_digest_algorithm(operation));
73 if (jni_operation == NULL) {
74 aws_jni_check_and_clear_exception(env);
75 goto clean_up;
76 }
77
78 /**
79 * Invoke TlsKeyOperationHandler.performOperation() through the invokePerformOperation
80 * function. This function will also catch any exceptions and clear the operation
81 * with an exception should it occur.
82 */
83 (*env)->CallStaticVoidMethod(
84 env,
85 tls_key_operation_properties.cls,
86 tls_key_operation_properties.invoke_operation_id,
87 op_handler->jni_custom_key_op,
88 jni_operation);
89 /**
90 * This should never fail because the function we're calling, invokePerformOperation,
91 * wraps the user callback in a try-catch block that will catch any exceptions.
92 */
93 AWS_FATAL_ASSERT(!aws_jni_check_and_clear_exception(env));
94 success = true;
95
96 clean_up:
97 if (jni_input_data) {
98 (*env)->DeleteLocalRef(env, jni_input_data);
99 }
100 if (jni_operation) {
101 (*env)->DeleteLocalRef(env, jni_operation);
102 }
103 if (!success) {
104 aws_tls_key_operation_complete_with_error(operation, AWS_ERROR_UNKNOWN);
105 }
106
107 /* Release the Java ENV */
108 aws_jni_release_thread_env(op_handler->jvm, env);
109 }
110
s_aws_custom_key_op_handler_destroy(struct aws_custom_key_op_handler * key_op_handler)111 static void s_aws_custom_key_op_handler_destroy(struct aws_custom_key_op_handler *key_op_handler) {
112
113 struct aws_jni_custom_key_op_handler *op_handler = (struct aws_jni_custom_key_op_handler *)key_op_handler->impl;
114
115 /* Get the Java ENV */
116 JNIEnv *env = aws_jni_acquire_thread_env(op_handler->jvm);
117 if (env == NULL) {
118 /* JVM is likely shutting down. Do not crash but log error. */
119 AWS_LOGF_ERROR(
120 AWS_LS_COMMON_IO, "java_custom_key_op_handler=%p destroy: Could not get Java ENV!", (void *)op_handler);
121 return;
122 }
123
124 /* Release the global reference */
125 if (op_handler->jni_custom_key_op) {
126 (*env)->DeleteGlobalRef(env, op_handler->jni_custom_key_op);
127 }
128
129 /* Release the Java ENV */
130 aws_jni_release_thread_env(op_handler->jvm, env);
131
132 /* Release the Java struct */
133 aws_mem_release(op_handler->allocator, op_handler);
134 }
135
136 static struct aws_custom_key_op_handler_vtable s_aws_custom_key_op_handler_vtable = {
137 .on_key_operation = s_aws_custom_key_op_handler_perform_operation,
138 };
139
aws_custom_key_op_handler_java_new(JNIEnv * env,jobject jni_custom_key_op)140 struct aws_custom_key_op_handler *aws_custom_key_op_handler_java_new(JNIEnv *env, jobject jni_custom_key_op) {
141
142 struct aws_allocator *allocator = aws_jni_get_allocator();
143
144 struct aws_jni_custom_key_op_handler *java_custom_key_op_handler =
145 aws_mem_calloc(allocator, 1, sizeof(struct aws_jni_custom_key_op_handler));
146
147 if ((*env)->GetJavaVM(env, &java_custom_key_op_handler->jvm) != 0) {
148 aws_jni_throw_runtime_exception(env, "failed to get JVM");
149 aws_mem_release(allocator, java_custom_key_op_handler);
150 return NULL;
151 }
152
153 aws_ref_count_init(
154 &java_custom_key_op_handler->base.ref_count,
155 &java_custom_key_op_handler->base,
156 (aws_simple_completion_callback *)s_aws_custom_key_op_handler_destroy);
157 java_custom_key_op_handler->base.vtable = &s_aws_custom_key_op_handler_vtable;
158 java_custom_key_op_handler->base.impl = (void *)java_custom_key_op_handler;
159 /* Make a global reference so the Java interface is kept alive */
160 java_custom_key_op_handler->jni_custom_key_op = (*env)->NewGlobalRef(env, jni_custom_key_op);
161 AWS_FATAL_ASSERT(java_custom_key_op_handler->jni_custom_key_op != NULL);
162 java_custom_key_op_handler->allocator = allocator;
163
164 AWS_LOGF_DEBUG(
165 AWS_LS_COMMON_IO,
166 "java_custom_key_op_handler=%p: Initalizing Custom Key Operations",
167 (void *)java_custom_key_op_handler);
168
169 return &java_custom_key_op_handler->base;
170 }
171
aws_custom_key_op_handler_java_release(struct aws_custom_key_op_handler * custom_key_op_handler)172 void aws_custom_key_op_handler_java_release(struct aws_custom_key_op_handler *custom_key_op_handler) {
173
174 if (custom_key_op_handler == NULL) {
175 return;
176 }
177 struct aws_jni_custom_key_op_handler *java_custom_key_op_handler =
178 (struct aws_jni_custom_key_op_handler *)custom_key_op_handler->impl;
179
180 AWS_LOGF_DEBUG(
181 AWS_LS_COMMON_IO,
182 "java_custom_key_op_handler=%p: Releasing Custom Key Operations (may destroy custom key operations if "
183 "this Java class holds the last reference)",
184 (void *)java_custom_key_op_handler);
185
186 /**
187 * Release the reference (which will only clean everything up if this is the last thing holding a reference)
188 */
189 aws_custom_key_op_handler_release(&java_custom_key_op_handler->base);
190 }
191