in source/s2n/s2n_tls_channel_handler.c [630:808]
static void s_s2n_pkcs11_async_pkey_task(
struct aws_channel_task *channel_task,
void *arg,
enum aws_task_status status) {
struct s2n_handler *s2n_handler = AWS_CONTAINER_OF(channel_task, struct s2n_handler, async_pkey_task);
struct aws_channel_handler *handler = &s2n_handler->handler;
struct s2n_async_pkey_op *op = arg;
bool success = false;
uint8_t *input_data = NULL; /* allocated later */
struct aws_byte_buf output_buf; /* initialized later */
AWS_ZERO_STRUCT(output_buf);
/* if things started failing since this task was scheduled, just clean up and bail out */
if (status != AWS_TASK_STATUS_RUN_READY || s2n_handler->state != NEGOTIATION_ONGOING) {
goto clean_up;
}
AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: Running PKCS#11 async pkey task", (void *)handler);
/* We check all s2n_async_pkey_op functions for success,
* but they shouldn't fail if they're called correctly.
* Even if the output is bad, the failure will happen later in s2n_negotiate() */
uint32_t input_size = 0;
if (s2n_async_pkey_op_get_input_size(op, &input_size)) {
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Failed querying s2n async pkey op size", (void *)handler);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto error;
}
input_data = aws_mem_acquire(handler->alloc, input_size);
if (s2n_async_pkey_op_get_input(op, input_data, input_size)) {
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Failed querying s2n async pkey input", (void *)handler);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto error;
}
struct aws_byte_cursor input_cursor = aws_byte_cursor_from_array(input_data, input_size);
s2n_async_pkey_op_type op_type = 0;
if (s2n_async_pkey_op_get_op_type(op, &op_type)) {
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Failed querying s2n async pkey op type", (void *)handler);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto error;
}
/* Gather additional information if this is a SIGN operation */
enum aws_tls_signature_algorithm aws_sign_alg = 0;
enum aws_tls_hash_algorithm aws_digest_alg = 0;
if (op_type == S2N_ASYNC_SIGN) {
s2n_tls_signature_algorithm s2n_sign_alg = 0;
if (s2n_connection_get_selected_client_cert_signature_algorithm(s2n_handler->connection, &s2n_sign_alg)) {
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Failed getting s2n client cert signature algorithm", (void *)handler);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto error;
}
aws_sign_alg = s_s2n_to_aws_signature_algorithm(s2n_sign_alg);
if (aws_sign_alg == AWS_TLS_SIGNATURE_UNKNOWN) {
AWS_LOGF_ERROR(
AWS_LS_IO_TLS,
"id=%p: Cannot sign with s2n_tls_signature_algorithm=%d. Algorithm currently unsupported",
(void *)handler,
s2n_sign_alg);
aws_raise_error(AWS_IO_TLS_SIGNATURE_ALGORITHM_UNSUPPORTED);
goto error;
}
s2n_tls_hash_algorithm s2n_digest_alg = 0;
if (s2n_connection_get_selected_client_cert_digest_algorithm(s2n_handler->connection, &s2n_digest_alg)) {
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Failed getting s2n client cert digest algorithm", (void *)handler);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto error;
}
aws_digest_alg = s_s2n_to_aws_hash_algorithm(s2n_digest_alg);
if (aws_digest_alg == AWS_TLS_HASH_UNKNOWN) {
AWS_LOGF_ERROR(
AWS_LS_IO_TLS,
"id=%p: Cannot sign digest created with s2n_tls_hash_algorithm=%d. Algorithm currently unsupported",
(void *)handler,
s2n_digest_alg);
aws_raise_error(AWS_IO_TLS_DIGEST_ALGORITHM_UNSUPPORTED);
goto error;
}
}
/*********** BEGIN CRITICAL SECTION ***********/
aws_mutex_lock(&s2n_handler->s2n_ctx->pkcs11.session_lock);
bool success_while_locked = false;
switch (op_type) {
case S2N_ASYNC_DECRYPT:
if (aws_pkcs11_lib_decrypt(
s2n_handler->s2n_ctx->pkcs11.lib,
s2n_handler->s2n_ctx->pkcs11.session_handle,
s2n_handler->s2n_ctx->pkcs11.private_key_handle,
s2n_handler->s2n_ctx->pkcs11.private_key_type,
input_cursor,
handler->alloc,
&output_buf)) {
AWS_LOGF_ERROR(
AWS_LS_IO_TLS,
"id=%p: PKCS#11 decrypt failed, error %s",
(void *)handler,
aws_error_name(aws_last_error()));
goto unlock;
}
break;
case S2N_ASYNC_SIGN:
if (aws_pkcs11_lib_sign(
s2n_handler->s2n_ctx->pkcs11.lib,
s2n_handler->s2n_ctx->pkcs11.session_handle,
s2n_handler->s2n_ctx->pkcs11.private_key_handle,
s2n_handler->s2n_ctx->pkcs11.private_key_type,
input_cursor,
handler->alloc,
aws_digest_alg,
aws_sign_alg,
&output_buf)) {
AWS_LOGF_ERROR(
AWS_LS_IO_TLS,
"id=%p: PKCS#11 sign failed, error %s",
(void *)handler,
aws_error_name(aws_last_error()));
goto unlock;
}
break;
default:
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Unknown s2n_async_pkey_op_type:%d", (void *)handler, (int)op_type);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto unlock;
}
success_while_locked = true;
unlock:
aws_mutex_unlock(&s2n_handler->s2n_ctx->pkcs11.session_lock);
/*********** END CRITICAL SECTION ***********/
if (!success_while_locked) {
goto error;
}
AWS_LOGF_TRACE(
AWS_LS_IO_TLS, "id=%p: PKCS#11 operation complete. output-size:%zu", (void *)handler, output_buf.len);
if (s2n_async_pkey_op_set_output(op, output_buf.buffer, output_buf.len)) {
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Failed setting output on s2n async pkey op", (void *)handler);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto error;
}
if (s2n_async_pkey_op_apply(op, s2n_handler->connection)) {
AWS_LOGF_ERROR(AWS_LS_IO_TLS, "id=%p: Failed applying s2n async pkey op", (void *)handler);
aws_raise_error(AWS_ERROR_INVALID_STATE);
goto error;
}
/* Success! */
success = true;
goto clean_up;
error:
aws_channel_shutdown(s2n_handler->slot->channel, aws_last_error());
clean_up:
s2n_async_pkey_op_free(op);
aws_mem_release(handler->alloc, input_data);
aws_byte_buf_clean_up(&output_buf);
if (success) {
s_drive_negotiation(handler);
}
}