napi_value aws_napi_io_tls_ctx_new()

in source/io.c [219:442]


napi_value aws_napi_io_tls_ctx_new(napi_env env, napi_callback_info info) {

    struct aws_allocator *alloc = aws_napi_get_allocator();
    napi_status status = napi_ok;
    (void)status;

    napi_value node_args[12];
    size_t num_args = AWS_ARRAY_SIZE(node_args);
    napi_value *arg = &node_args[0];
    if (napi_ok != napi_get_cb_info(env, info, &num_args, node_args, NULL, NULL)) {
        napi_throw_error(env, NULL, "Failed to retreive callback information");
        return NULL;
    }
    if (num_args != AWS_ARRAY_SIZE(node_args)) {
        napi_throw_error(env, NULL, "aws_nodejs_io_client_tls_ctx_new needs exactly 12 arguments");
        return NULL;
    }

    napi_value result = NULL;

#ifdef __APPLE__
    struct aws_byte_buf pkcs12_path;
    AWS_ZERO_STRUCT(pkcs12_path);
    struct aws_byte_buf pkcs12_pwd;
    AWS_ZERO_STRUCT(pkcs12_pwd);
#endif

    struct aws_tls_ctx_options ctx_options;
    AWS_ZERO_STRUCT(ctx_options);

    struct aws_string *ca_path = NULL;
    struct aws_string *ca_file = NULL;

    struct aws_byte_buf certificate;
    AWS_ZERO_STRUCT(certificate);
    struct aws_byte_buf private_key;
    AWS_ZERO_STRUCT(private_key);
    struct aws_byte_buf ca_buf;
    AWS_ZERO_STRUCT(ca_buf);

    struct aws_string *cert_path = NULL;
    struct aws_string *pkey_path = NULL;
    struct aws_string *alpn_list = NULL;

    uint32_t min_tls_version = AWS_IO_TLS_VER_SYS_DEFAULTS;
    napi_value node_tls_version = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_tls_version)) {
        napi_value node_number;
        if (napi_ok != napi_coerce_to_number(env, node_tls_version, &node_number)) {
            napi_throw_type_error(env, NULL, "min_tls_version must be an enum/Number (or convertible to a Number)");
            return result;
        }
        status = napi_get_value_uint32(env, node_number, &min_tls_version);
        AWS_FATAL_ASSERT(status == napi_ok); /* We coerced the value to a number, so this must return ok */
    }

    napi_value node_ca_file = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_ca_file)) {
        ca_file = aws_string_new_from_napi(env, node_ca_file);
        if (!ca_file) {
            napi_throw_type_error(env, NULL, "ca_filepath must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_ca_path = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_ca_path)) {
        ca_path = aws_string_new_from_napi(env, node_ca_path);
        if (!ca_path) {
            napi_throw_type_error(env, NULL, "ca_dirpath must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_ca_buf = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_ca_buf)) {
        if (aws_byte_buf_init_from_napi(&ca_buf, env, node_ca_buf)) {
            napi_throw_type_error(env, NULL, "certificate_authority must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_alpn = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_alpn)) {
        alpn_list = aws_string_new_from_napi(env, node_alpn);
        if (!alpn_list) {
            napi_throw_type_error(env, NULL, "alpn_list must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_cert_path = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_cert_path)) {
        cert_path = aws_string_new_from_napi(env, node_cert_path);
        if (!cert_path) {
            napi_throw_type_error(env, NULL, "cert_path must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_cert_buf = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_cert_buf)) {
        if (aws_byte_buf_init_from_napi(&certificate, env, node_cert_buf)) {
            napi_throw_type_error(env, NULL, "certificate must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_key_path = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_key_path)) {
        pkey_path = aws_string_new_from_napi(env, node_key_path);
        if (!pkey_path) {
            napi_throw_type_error(env, NULL, "private_key_path must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_key_buf = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_key_buf)) {
        if (aws_byte_buf_init_from_napi(&private_key, env, node_key_buf)) {
            napi_throw_type_error(env, NULL, "private_key must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    napi_value node_pkcs12_path = *arg++;
    napi_value node_pkcs12_password = *arg++;
    (void)node_pkcs12_path;
    (void)node_pkcs12_password;
#ifdef __APPLE__
    if (!aws_napi_is_null_or_undefined(env, node_pkcs12_path)) {
        if (napi_ok != aws_byte_buf_init_from_napi(&pkcs12_path, env, node_pkcs12_path)) {
            napi_throw_type_error(env, NULL, "pkcs12_path must be a String (or convertible to a String)");
            goto cleanup;
        }
    }

    if (!aws_napi_is_null_or_undefined(env, node_pkcs12_password)) {
        if (napi_ok != aws_byte_buf_init_from_napi(&pkcs12_pwd, env, node_pkcs12_password)) {
            napi_throw_type_error(env, NULL, "pkcs12_password must be a String (or convertible to a String)");
            goto cleanup;
        }
    }
#endif /* __APPLE__ */

    bool verify_peer = true;
    napi_value node_verify_peer = *arg++;
    if (!aws_napi_is_null_or_undefined(env, node_verify_peer)) {
        napi_value node_bool;
        if (napi_ok != napi_coerce_to_bool(env, node_verify_peer, &node_bool)) {
            napi_throw_type_error(env, NULL, "verify_peer must be a boolean (or convertible to a boolean)");
            goto cleanup;
        }

        status = napi_get_value_bool(env, node_bool, &verify_peer);
        AWS_FATAL_ASSERT(status == napi_ok);
    }

    if (certificate.buffer && private_key.buffer) {
        struct aws_byte_cursor cert_cursor = aws_byte_cursor_from_buf(&certificate);
        struct aws_byte_cursor pkey_cursor = aws_byte_cursor_from_buf(&private_key);
        if (aws_tls_ctx_options_init_client_mtls(&ctx_options, alloc, &cert_cursor, &pkey_cursor)) {
            aws_napi_throw_last_error(env);
            goto cleanup;
        }
    } else if (cert_path && pkey_path) {
        if (aws_tls_ctx_options_init_client_mtls_from_path(
                &ctx_options, alloc, aws_string_c_str(cert_path), aws_string_c_str(pkey_path))) {
            aws_napi_throw_last_error(env);
            goto cleanup;
        }
    } else {
        aws_tls_ctx_options_init_default_client(&ctx_options, alloc);
    }

    if (ca_buf.buffer) {
        struct aws_byte_cursor ca_cursor = aws_byte_cursor_from_buf(&ca_buf);
        if (aws_tls_ctx_options_override_default_trust_store(&ctx_options, &ca_cursor)) {
            aws_napi_throw_last_error(env);
            goto cleanup;
        }
    } else if (ca_path || ca_file) {
        if (aws_tls_ctx_options_override_default_trust_store_from_path(
                &ctx_options, ca_path ? aws_string_c_str(ca_path) : NULL, ca_file ? aws_string_c_str(ca_file) : NULL)) {
            aws_napi_throw_last_error(env);
            goto cleanup;
        }
    }

    if (alpn_list) {
        aws_tls_ctx_options_set_alpn_list(&ctx_options, aws_string_c_str(alpn_list));
    }

    aws_tls_ctx_options_set_verify_peer(&ctx_options, verify_peer);

    struct aws_tls_ctx *tls_ctx = aws_tls_client_ctx_new(alloc, &ctx_options);
    if (!tls_ctx) {
        napi_throw_error(env, NULL, "Unable to create TLS context");
        goto cleanup;
    }

    napi_value node_external;
    if (napi_ok != napi_create_external(env, tls_ctx, s_tls_ctx_finalize, NULL, &node_external)) {
        napi_throw_error(env, NULL, "Failed create n-api external");
        goto cleanup;
    }

    result = node_external;

cleanup:
#ifdef __APPLE__
    aws_byte_buf_clean_up_secure(&pkcs12_path);
    aws_byte_buf_clean_up_secure(&pkcs12_pwd);
#endif
    aws_string_destroy_secure(cert_path);
    aws_byte_buf_clean_up_secure(&certificate);
    aws_string_destroy_secure(pkey_path);
    aws_byte_buf_clean_up_secure(&private_key);
    aws_byte_buf_clean_up_secure(&ca_buf);
    aws_string_destroy(alpn_list);
    aws_tls_ctx_options_clean_up(&ctx_options);

    return result;
}